diff options
author | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2009-02-12 13:02:05 +0000 |
---|---|---|
committer | Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> | 2009-02-12 13:02:05 +0000 |
commit | 8695678c5c6792ac1b055dd121e3c68caec1ff48 (patch) | |
tree | 537691cdfbc8b9d64193081ba1208e8504a3a883 /lib | |
parent | beba2ea4d45c64bb447d82b3b43342ea9de45f66 (diff) | |
parent | df8e4cdc8c8d2efe62a2410762424b4ac61ca077 (diff) |
Merge branch 'master' into requestotron-tubes-and-caps-with-complex-types-with-gibber-listener-REBASED
Conflicts:
.gitignore
Diffstat (limited to 'lib')
37 files changed, 5563 insertions, 1 deletions
diff --git a/lib/gibber/AUTHORS b/lib/gibber/AUTHORS new file mode 100644 index 00000000..93b800c1 --- /dev/null +++ b/lib/gibber/AUTHORS @@ -0,0 +1 @@ +Sjoerd Simons <sjoerd@luon.net> diff --git a/lib/gibber/COPYING b/lib/gibber/COPYING new file mode 100644 index 00000000..e3819249 --- /dev/null +++ b/lib/gibber/COPYING @@ -0,0 +1,542 @@ +Most of Salut is licensed under the GNU Lesser General Public License, +as published by the Free Software Foundation and reproduced below: +either version 2.1 of the License, or (at your option) any later version. + +xep.xsl in the the tools/ directory, used to generate HTML documentation +for the Clique protocol, is copyright 1999-2008 by the +XMPP Standards Foundation (XSF) and is released under a MIT-style +license, reproduced below. + +------------------------------------------------------------------------ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + +------------------------------------------------------------------------ + +License of tools/xep.xsl: + + Copyright (c) 1999 - 2008 XMPP Standards Foundation + + 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. diff --git a/lib/gibber/Makefile.am b/lib/gibber/Makefile.am index 975e8d33..f324db10 100644 --- a/lib/gibber/Makefile.am +++ b/lib/gibber/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS=examples +SUBDIRS = examples tests noinst_LTLIBRARIES = libgibber.la diff --git a/lib/gibber/tests/Makefile.am b/lib/gibber/tests/Makefile.am new file mode 100644 index 00000000..cc137228 --- /dev/null +++ b/lib/gibber/tests/Makefile.am @@ -0,0 +1,122 @@ +CLEANFILES= + +include $(top_srcdir)/rules/check.mak + +SUPPRESSIONS=valgrind.supp dlopen.supp + +# Teach it how to make libgibber.la +$(top_builddir)/lib/gibber/libgibber.la: + ${MAKE} -C $(top_builddir)/lib/gibber libgibber.la + +.PHONY: $(top_builddir)/lib/gibber/libgibber.la + +TESTS = \ + run-xmpp-connection-test.sh + +check_PROGRAMS = \ + test-xmpp-connection \ + test-r-multicast-transport-io + +check_SCRIPTS = run-xmpp-connection-test.sh + +EXTRA_DIST = simplemeshtest.py mesh.py $(check_SCRIPTS) + +test_xmpp_connection_SOURCES = \ + test-xmpp-connection.c \ + test-transport.c \ + test-transport.h + +test_xmpp_connection_LDADD = \ + $(top_builddir)/lib/gibber/libgibber.la \ + $(AM_LDFLAGS) + +test_xmpp_connection_CFLAGS = \ + $(AM_CFLAGS) + +test_r_multicast_transport_io_SOURCES = \ + test-r-multicast-transport-io.c \ + test-transport.c \ + test-transport.h + +test_r_multicast_transport_io_LDADD = \ + $(top_builddir)/lib/gibber/libgibber.la \ + $(AM_LDFLAGS) + +test_r_multicast_transport_io_CFLAGS = \ + $(AM_CFLAGS) + + +if HAVE_CHECK +check_PROGRAMS += check-main +TESTS += check-main +check_main_SOURCES = \ + check-main.c \ + check-helpers.c \ + check-helpers.h \ + check-gibber.h \ + check-gibber-xmpp-node.c \ + check-gibber-xmpp-reader.c \ + check-gibber-r-multicast-causal-transport.c \ + check-gibber-resolver.c \ + test-resolver.c \ + test-resolver.h \ + test-transport.c \ + test-transport.h \ + check-gibber-xmpp-connection.c \ + check-gibber-r-multicast-packet.c \ + check-gibber-r-multicast-sender.c \ + check-gibber-xmpp-stanza.c \ + check-gibber-iq-helper.c \ + check-gibber-listener.c \ + check-gibber-xmpp-connection-listener.c \ + check-gibber-xmpp-error.c + +check_main_LDADD = \ + @CHECK_LIBS@ \ + $(top_builddir)/lib/gibber/libgibber.la \ + $(AM_LDFLAGS) + +check_main_CFLAGS = \ + @CHECK_CFLAGS@ \ + $(AM_CFLAGS) + +if HAVE_LIBSASL2 + check_main_SOURCES += \ + check-gibber-sasl-auth.c \ + test-sasl-auth-server.c \ + test-sasl-auth-server.h + + check_main_LDADD += @LIBSASL2_LIBS@ + check_main_CFLAGS += @LIBSASL2_CFLAGS@ +endif + +endif + +AM_CFLAGS = $(ERROR_CFLAGS) @GLIB_CFLAGS@ @LIBXML2_CFLAGS@ @DBUS_CFLAGS@ \ + -I $(top_srcdir) -I $(top_builddir) \ + -I $(top_srcdir)/lib -I $(top_builddir)/lib + +AM_LDFLAGS = @GLIB_LIBS@ + +# Coding style checks +check_c_sources = \ + $(test_xmpp_connection_SOURCES) \ + $(test_r_multicast_transport_io_SOURCES) + +if HAVE_CHECK + check_c_sources += $(check_main_SOURCES) +endif + +include $(top_srcdir)/tools/check-coding-style.mk +check-local: check-coding-style + +clean-local: + -rm -rf outputs + -rm -f sasl-test.db + +SUBDIRS = inputs + +$(check_SCRIPTS): always-run + chmod +x $(srcdir)/$@ + +.PHONY: always-run diff --git a/lib/gibber/tests/check-gibber-iq-helper.c b/lib/gibber/tests/check-gibber-iq-helper.c new file mode 100644 index 00000000..5a79c452 --- /dev/null +++ b/lib/gibber/tests/check-gibber-iq-helper.c @@ -0,0 +1,432 @@ +/* + * check-gibber-iq-helper.c - Test for GibberIqHelper + * Copyright (C) 2007 Collabora Ltd. + * @author Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dbus/dbus-glib.h> + +#include <gibber/gibber-xmpp-stanza.h> +#include <gibber/gibber-iq-helper.h> +#include <gibber/gibber-xmpp-error.h> +#include <gibber/gibber-namespaces.h> + +#include <check.h> +#include "check-helpers.h" +#include "check-gibber.h" + +#include "test-transport.h" + +gboolean received_reply = FALSE; + +static gboolean +send_hook (GibberTransport *transport, + const guint8 *data, + gsize length, + GError **error, + gpointer user_data) +{ + test_transport_write (TEST_TRANSPORT (transport), data, length); + return TRUE; +} + +static GibberXmppConnection * +create_xmpp_connection (void) +{ + GibberXmppConnection *xmpp_connection; + TestTransport *transport; + + transport = test_transport_new (send_hook, NULL); + xmpp_connection = gibber_xmpp_connection_new (GIBBER_TRANSPORT (transport)); + gibber_xmpp_connection_open (xmpp_connection, "to", "from", "1.0"); + + g_object_unref (transport); + + return xmpp_connection; +} + +START_TEST (test_iq_helper_new) +{ + GibberXmppConnection *xmpp_connection = create_xmpp_connection (); + GibberIqHelper *iq_helper = gibber_iq_helper_new (xmpp_connection); + fail_unless (iq_helper != NULL); + g_object_unref (xmpp_connection); + g_object_unref (iq_helper); +} +END_TEST + +static void +reply_func (GibberIqHelper *helper, + GibberXmppStanza *sent_stanza, + GibberXmppStanza *reply_stanza, + GObject *object, + gpointer user_data) +{ + received_reply = TRUE; +} + +static void +send_stanza_and_reply (GibberXmppConnection *xmpp_connection, + GibberIqHelper *iq_helper, + GibberXmppStanza *stanza, + GibberXmppStanza *reply) +{ + gboolean result; + + if (stanza != NULL) + { + result = gibber_iq_helper_send_with_reply (iq_helper, stanza, reply_func, + NULL, NULL, NULL); + fail_unless (result); + } + + if (reply != NULL) + { + result = gibber_xmpp_connection_send (xmpp_connection, reply, NULL); + fail_unless (result); + } + + while (g_main_context_iteration (NULL, FALSE)) + ; + +} + +START_TEST (test_send_with_reply) +{ + GibberXmppConnection *xmpp_connection = create_xmpp_connection (); + GibberIqHelper *iq_helper = gibber_iq_helper_new (xmpp_connection); + GibberXmppStanza *stanza, *reply; + + received_reply = FALSE; + + stanza = gibber_xmpp_stanza_build (GIBBER_STANZA_TYPE_IQ, + GIBBER_STANZA_SUB_TYPE_SET, + "from", "to", + GIBBER_NODE_ATTRIBUTE, "id", "69", + GIBBER_STANZA_END); + + /* Reply of the stanza */ + reply = gibber_xmpp_stanza_build (GIBBER_STANZA_TYPE_IQ, + GIBBER_STANZA_SUB_TYPE_RESULT, + "to", "from", + GIBBER_NODE_ATTRIBUTE, "id", "69", + GIBBER_STANZA_END); + + send_stanza_and_reply (xmpp_connection, iq_helper, stanza, reply); + fail_unless (received_reply); + + g_object_unref (stanza); + g_object_unref (reply); + g_object_unref (xmpp_connection); + g_object_unref (iq_helper); +} +END_TEST + +START_TEST (test_send_without_reply) +{ + GibberXmppConnection *xmpp_connection = create_xmpp_connection (); + GibberIqHelper *iq_helper = gibber_iq_helper_new (xmpp_connection); + GibberXmppStanza *stanza; + + received_reply = FALSE; + + stanza = gibber_xmpp_stanza_build (GIBBER_STANZA_TYPE_IQ, + GIBBER_STANZA_SUB_TYPE_SET, + "from", "to", + GIBBER_NODE_ATTRIBUTE, "id", "69", + GIBBER_STANZA_END); + + send_stanza_and_reply (xmpp_connection, iq_helper, stanza, NULL); + fail_unless (!received_reply); + + g_object_unref (stanza); + g_object_unref (xmpp_connection); + g_object_unref (iq_helper); +} +END_TEST + +START_TEST (test_send_with_bad_reply_type) +{ + GibberXmppConnection *xmpp_connection = create_xmpp_connection (); + GibberIqHelper *iq_helper = gibber_iq_helper_new (xmpp_connection); + GibberXmppStanza *stanza, *reply; + + received_reply = FALSE; + + stanza = gibber_xmpp_stanza_build (GIBBER_STANZA_TYPE_IQ, + GIBBER_STANZA_SUB_TYPE_SET, + "from", "to", + GIBBER_NODE_ATTRIBUTE, "id", "69", + GIBBER_STANZA_END); + + /* Reply can't be of sub type "get" */ + reply = gibber_xmpp_stanza_build (GIBBER_STANZA_TYPE_IQ, + GIBBER_STANZA_SUB_TYPE_GET, + "to", "from", + GIBBER_NODE_ATTRIBUTE, "id", "69", + GIBBER_STANZA_END); + + send_stanza_and_reply (xmpp_connection, iq_helper, stanza, reply); + fail_unless (!received_reply); + + g_object_unref (stanza); + g_object_unref (reply); + g_object_unref (xmpp_connection); + g_object_unref (iq_helper); +} +END_TEST + +START_TEST (test_send_without_id) +{ + GibberXmppConnection *xmpp_connection = create_xmpp_connection (); + GibberIqHelper *iq_helper = gibber_iq_helper_new (xmpp_connection); + GibberXmppStanza *stanza, *reply; + gboolean result; + const gchar *id; + + received_reply = FALSE; + + stanza = gibber_xmpp_stanza_build (GIBBER_STANZA_TYPE_IQ, + GIBBER_STANZA_SUB_TYPE_SET, + "from", "to", + GIBBER_STANZA_END); + + result = gibber_iq_helper_send_with_reply (iq_helper, stanza, reply_func, + NULL, NULL, NULL); + fail_unless (result); + + /* gibber_iq_helper_send_with_reply generated an id */ + id = gibber_xmpp_node_get_attribute (stanza->node, "id"); + + reply = gibber_xmpp_stanza_build (GIBBER_STANZA_TYPE_IQ, + GIBBER_STANZA_SUB_TYPE_RESULT, + "to", "from", + GIBBER_NODE_ATTRIBUTE, "id", id, + GIBBER_STANZA_END); + + result = gibber_xmpp_connection_send (xmpp_connection, reply, NULL); + fail_unless (result); + + while (g_main_context_iteration (NULL, FALSE)) + ; + + fail_unless (received_reply); + + g_object_unref (stanza); + g_object_unref (reply); + g_object_unref (xmpp_connection); + g_object_unref (iq_helper); +} +END_TEST + +START_TEST (test_new_result_reply) +{ + GibberXmppConnection *xmpp_connection = create_xmpp_connection (); + GibberIqHelper *iq_helper = gibber_iq_helper_new (xmpp_connection); + GibberXmppStanza *stanza, *reply; + gboolean result; + + received_reply = FALSE; + + stanza = gibber_xmpp_stanza_build (GIBBER_STANZA_TYPE_IQ, + GIBBER_STANZA_SUB_TYPE_SET, + "from", "to", + GIBBER_STANZA_END); + + result = gibber_iq_helper_send_with_reply (iq_helper, stanza, reply_func, + NULL, NULL, NULL); + fail_unless (result); + + reply = gibber_iq_helper_new_result_reply (stanza); + fail_unless (reply != NULL); + fail_unless (strcmp (reply->node->name, "iq") == 0); + fail_unless (strcmp (gibber_xmpp_node_get_attribute (reply->node, "type"), + "result") == 0); + result = gibber_xmpp_connection_send (xmpp_connection, reply, NULL); + fail_unless (result); + + while (g_main_context_iteration (NULL, FALSE)) + ; + + fail_unless (received_reply); + + g_object_unref (stanza); + g_object_unref (reply); + g_object_unref (xmpp_connection); + g_object_unref (iq_helper); +} +END_TEST + +START_TEST (test_new_error_reply) +{ + GibberXmppConnection *xmpp_connection = create_xmpp_connection (); + GibberIqHelper *iq_helper = gibber_iq_helper_new (xmpp_connection); + GibberXmppStanza *stanza, *reply; + GibberXmppNode *error_node, *node; + gboolean result; + + received_reply = FALSE; + + stanza = gibber_xmpp_stanza_build (GIBBER_STANZA_TYPE_IQ, + GIBBER_STANZA_SUB_TYPE_SET, + "from", "to", + GIBBER_STANZA_END); + + result = gibber_iq_helper_send_with_reply (iq_helper, stanza, reply_func, + NULL, NULL, NULL); + fail_unless (result); + + reply = gibber_iq_helper_new_error_reply (stanza, + XMPP_ERROR_BAD_REQUEST, "test"); + fail_unless (reply != NULL); + fail_unless (strcmp (reply->node->name, "iq") == 0); + fail_unless (strcmp (gibber_xmpp_node_get_attribute (reply->node, "type"), + "error") == 0); + + error_node = gibber_xmpp_node_get_child (reply->node, "error"); + fail_if (error_node == NULL); + fail_if (strcmp (gibber_xmpp_node_get_attribute (error_node, "code"), + "400") != 0); + fail_if (strcmp (gibber_xmpp_node_get_attribute (error_node, "type"), + "modify") != 0); + + node = gibber_xmpp_node_get_child_ns (error_node, "bad-request", + GIBBER_XMPP_NS_STANZAS); + fail_if (node == NULL); + + node = gibber_xmpp_node_get_child (error_node, "text"); + fail_if (node == NULL); + fail_if (strcmp (node->content, "test") != 0); + + result = gibber_xmpp_connection_send (xmpp_connection, reply, NULL); + fail_unless (result); + + while (g_main_context_iteration (NULL, FALSE)) + ; + + fail_unless (received_reply); + + g_object_unref (stanza); + g_object_unref (reply); + g_object_unref (xmpp_connection); + g_object_unref (iq_helper); +} +END_TEST + +START_TEST (test_send_with_object_living) +{ + GibberXmppConnection *xmpp_connection = create_xmpp_connection (); + GibberIqHelper *iq_helper = gibber_iq_helper_new (xmpp_connection); + GibberXmppStanza *stanza, *reply; + gboolean result; + GObject *object; + + received_reply = FALSE; + + /* We don't care about the TestTransport, we just need a GObject */ + object = g_object_new (TEST_TYPE_TRANSPORT, NULL); + + stanza = gibber_xmpp_stanza_build (GIBBER_STANZA_TYPE_IQ, + GIBBER_STANZA_SUB_TYPE_SET, + "from", "to", + GIBBER_STANZA_END); + + result = gibber_iq_helper_send_with_reply (iq_helper, stanza, reply_func, + object, NULL, NULL); + fail_unless (result); + + reply = gibber_iq_helper_new_result_reply (stanza); + fail_unless (reply != NULL); + result = gibber_xmpp_connection_send (xmpp_connection, reply, NULL); + fail_unless (result); + + while (g_main_context_iteration (NULL, FALSE)) + ; + + fail_unless (received_reply); + + g_object_unref (stanza); + g_object_unref (reply); + g_object_unref (object); + g_object_unref (xmpp_connection); + g_object_unref (iq_helper); +} +END_TEST + +START_TEST (test_send_with_object_destroyed) +{ + GibberXmppConnection *xmpp_connection = create_xmpp_connection (); + GibberIqHelper *iq_helper = gibber_iq_helper_new (xmpp_connection); + GibberXmppStanza *stanza, *reply; + gboolean result; + GObject *object; + + received_reply = FALSE; + + /* We don't care about the TestTransport, we just need a GObject */ + object = g_object_new (TEST_TYPE_TRANSPORT, NULL); + + stanza = gibber_xmpp_stanza_build (GIBBER_STANZA_TYPE_IQ, + GIBBER_STANZA_SUB_TYPE_SET, + "from", "to", + GIBBER_STANZA_END); + + result = gibber_iq_helper_send_with_reply (iq_helper, stanza, reply_func, + object, NULL, NULL); + fail_unless (result); + + g_object_unref (object); + + reply = gibber_iq_helper_new_result_reply (stanza); + fail_unless (reply != NULL); + result = gibber_xmpp_connection_send (xmpp_connection, reply, NULL); + fail_unless (result); + + while (g_main_context_iteration (NULL, FALSE)) + ; + + /* Object was destroyed before we send the reply so we don't receive + * the reply */ + fail_unless (!received_reply); + + g_object_unref (stanza); + g_object_unref (reply); + g_object_unref (xmpp_connection); + g_object_unref (iq_helper); +} +END_TEST + +TCase * +make_gibber_iq_helper_tcase (void) +{ + TCase *tc = tcase_create ("IQ helper"); + tcase_add_test (tc, test_iq_helper_new); + tcase_add_test (tc, test_send_with_reply); + tcase_add_test (tc, test_send_without_reply); + tcase_add_test (tc, test_send_with_bad_reply_type); + tcase_add_test (tc, test_send_without_id); + tcase_add_test (tc, test_new_result_reply); + tcase_add_test (tc, test_new_error_reply); + tcase_add_test (tc, test_send_with_object_living); + tcase_add_test (tc, test_send_with_object_destroyed); + + return tc; +} diff --git a/lib/gibber/tests/check-gibber-listener.c b/lib/gibber/tests/check-gibber-listener.c new file mode 100644 index 00000000..4a1bce06 --- /dev/null +++ b/lib/gibber/tests/check-gibber-listener.c @@ -0,0 +1,211 @@ +/* + * check-gibber-listener.c - Test for GibberListener + * Copyright (C) 2007, 2008 Collabora Ltd. + * @author Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> + * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <unistd.h> + +#include <gibber/gibber-tcp-transport.h> +#include <gibber/gibber-unix-transport.h> +#include <gibber/gibber-listener.h> + +#include <check.h> +#include "check-gibber.h" + +gboolean got_connection; +gboolean signalled; + +static void +new_connection_cb (GibberListener *listener, + GibberTransport *connection, + struct sockaddr *addr, + guint size, + GMainLoop *loop) +{ + signalled = TRUE; + got_connection = TRUE; + g_main_loop_quit (loop); +} + +static void +disconnected_cb (GibberTransport *transport, GMainLoop *loop) +{ + signalled = TRUE; + got_connection = FALSE; + g_main_loop_quit (loop); +} + +static GibberTransport * +connect_to_port (int port, GMainLoop *loop) +{ + GibberTCPTransport *transport; + gchar sport[16]; + + g_snprintf (sport, 16, "%d", port); + + transport = gibber_tcp_transport_new (); + g_signal_connect (transport, "disconnected", + G_CALLBACK (disconnected_cb), loop); + + gibber_tcp_transport_connect (transport, "127.0.0.1", sport); + + return GIBBER_TRANSPORT (transport); +} + +START_TEST (test_unix_listen) +{ + GibberListener *listener_unix; + GibberUnixTransport *unix_transport; + int ret; + GMainLoop *mainloop; + GError *error = NULL; + gchar *path = "/tmp/check-gibber-listener-socket"; + + ret = unlink (path); + fail_if (ret == -1 && errno != ENOENT); + + mainloop = g_main_loop_new (NULL, FALSE); + + listener_unix = gibber_listener_new (); + fail_if (listener_unix == NULL); + + g_signal_connect (listener_unix, "new-connection", + G_CALLBACK (new_connection_cb), mainloop); + + ret = gibber_listener_listen_socket (listener_unix, path, FALSE, &error); + fail_if (ret != TRUE); + + unix_transport = gibber_unix_transport_new (); + ret = gibber_unix_transport_connect (unix_transport, path, &error); + fail_if (ret != TRUE); + + if (!signalled) + g_main_loop_run (mainloop); + + fail_if (!got_connection, "Failed to connect"); + + g_object_unref (listener_unix); + g_object_unref (unix_transport); + g_main_loop_unref (mainloop); +} END_TEST + +START_TEST (test_tcp_listen) +{ + GibberListener *listener; + GibberListener *listener_without_port; + GibberListener *listener2; + int ret, port; + GMainLoop *mainloop; + GibberTransport *transport; + GError *error = NULL; + + mainloop = g_main_loop_new (NULL, FALSE); + + /* tcp socket tests without a specified port */ + listener_without_port = gibber_listener_new (); + fail_if (listener_without_port == NULL); + + g_signal_connect (listener_without_port, "new-connection", + G_CALLBACK (new_connection_cb), mainloop); + + ret = gibber_listener_listen_tcp (listener_without_port, 0, &error); + fail_if (ret != TRUE); + port = gibber_listener_get_port (listener_without_port); + + signalled = FALSE; + transport = connect_to_port (port, mainloop); + if (!signalled) + g_main_loop_run (mainloop); + + fail_if (!got_connection, "Failed to connect"); + + g_object_unref (listener_without_port); + g_object_unref (transport); + + /* tcp socket tests with a specified port */ + listener = gibber_listener_new (); + fail_if (listener == NULL); + + g_signal_connect (listener, "new-connection", G_CALLBACK (new_connection_cb), + mainloop); + + for (port = 5298; port < 5400; port++) + { + if (gibber_listener_listen_tcp (listener, port, &error)) + break; + + fail_if (!g_error_matches (error, GIBBER_LISTENER_ERROR, + GIBBER_LISTENER_ERROR_ADDRESS_IN_USE)); + g_error_free (error); + error = NULL; + } + fail_if (port >= 5400); + fail_if (port != gibber_listener_get_port (listener)); + + /* try a second listener on the same port */ + listener2 = gibber_listener_new (); + fail_if (listener2 == NULL); + fail_if (gibber_listener_listen_tcp (listener2, port, &error)); + fail_if (!g_error_matches (error, GIBBER_LISTENER_ERROR, + GIBBER_LISTENER_ERROR_ADDRESS_IN_USE)); + g_object_unref (listener2); + g_error_free (error); + error = NULL; + + signalled = FALSE; + transport = connect_to_port (port, mainloop); + if (!signalled) + g_main_loop_run (mainloop); + + fail_if (!got_connection, "Failed to connect"); + + g_object_unref (listener); + g_object_unref (transport); + + /* listener is destroyed, connection should be refused now */ + signalled = FALSE; + transport = connect_to_port (port, mainloop); + + if (!signalled) + g_main_loop_run (mainloop); + + fail_if (got_connection, "Connected while listening should have stopped"); + + g_object_unref (transport); + g_main_loop_unref (mainloop); + +} END_TEST + +TCase * +make_gibber_listener_tcase (void) +{ + TCase *tc = tcase_create ("GibberListener"); + tcase_add_test (tc, test_tcp_listen); + tcase_add_test (tc, test_unix_listen); + return tc; +} diff --git a/lib/gibber/tests/check-gibber-r-multicast-causal-transport.c b/lib/gibber/tests/check-gibber-r-multicast-causal-transport.c new file mode 100644 index 00000000..8dc92782 --- /dev/null +++ b/lib/gibber/tests/check-gibber-r-multicast-causal-transport.c @@ -0,0 +1,550 @@ +/* + * check-gibber-r-multicast-causal-transport.c + * - R Multicast CausalTransport test + * Copyright (C) 2007 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <stdio.h> +#include <unistd.h> +#include <string.h> + +#include <gibber/gibber-r-multicast-causal-transport.h> +#include <gibber/gibber-r-multicast-packet.h> +#include "test-transport.h" +#include "check-gibber.h" + +#include <check.h> + +/* Numer of polls we expect the id generation to do */ +#define ID_GENERATION_EXPECTED_POLLS 3 + +/* Assume mtu is 1500, we want at least 3 packets */ +#define TEST_DATA_SIZE 3300 +GMainLoop *loop; + +static GibberRMulticastCausalTransport * +create_rmulticast_transport (TestTransport **testtransport, + const gchar *name, + test_transport_send_hook test_send_hook, + gpointer user_data) +{ + TestTransport *t; + GibberRMulticastCausalTransport *rmctransport; + + t = test_transport_new (test_send_hook, user_data); + fail_unless (t != NULL); + GIBBER_TRANSPORT (t)->max_packet_size = 150; + + rmctransport = gibber_r_multicast_causal_transport_new + (GIBBER_TRANSPORT(t), "test123"); + g_object_unref (t); + + if (testtransport != NULL) + { + *testtransport = t; + } + + test_transport_set_echoing (t, TRUE); + + return rmctransport; +} + +static void +rmulticast_connect (GibberRMulticastCausalTransport *transport) +{ + + fail_unless (transport != NULL); + + fail_unless (gibber_r_multicast_causal_transport_connect (transport, + FALSE, NULL)); +} + + +/* test depends test */ +struct { + gchar *name; + guint32 sender_id; + guint32 packet_id; + gboolean seen; +} senders[] = { + { "test0", 1, 0xff, FALSE }, + { "test1", 2, 0xffff, FALSE }, + { "test2", 3, 0xffffff, FALSE }, + { "test3", 4, 0xaaaaaa, FALSE }, + { "test4", 5, 0xabcdab, FALSE }, + { NULL, 0, 0, FALSE } +}; + +static gboolean +depends_send_hook (GibberTransport *transport, + const guint8 *data, + gsize length, + GError **error, + gpointer user_data) +{ + GibberRMulticastPacket *packet; + guint i, n; + + packet = gibber_r_multicast_packet_parse (data, length, NULL); + fail_unless (packet != NULL); + + if (packet->type == PACKET_TYPE_WHOIS_REQUEST) + { + GibberRMulticastPacket *reply; + guint8 *pdata; + gsize psize; + + for (i = 0; senders[i].name != NULL; i++) + { + if (senders[i].sender_id == packet->data.whois_request.sender_id) + { + break; + } + } + + if (senders[i].name == NULL && packet->sender == 0) + { + /* unique id polling */ + goto out; + } + + fail_unless (senders[i].name != NULL); + + reply = gibber_r_multicast_packet_new (PACKET_TYPE_WHOIS_REPLY, + senders[i].sender_id, transport->max_packet_size); + + gibber_r_multicast_packet_set_whois_reply_info (reply, + senders[i].name); + + pdata = gibber_r_multicast_packet_get_raw_data (reply, &psize); + test_transport_write (TEST_TRANSPORT(transport), pdata, psize); + g_object_unref (reply); + } + + if (packet->type != PACKET_TYPE_DATA) + { + goto out; + } + + fail_unless (packet->depends->len > 0); + + for (n = 0; n < packet->depends->len; n++) + { + for (i = 0; senders[i].name != NULL ; i++) + { + GibberRMulticastPacketSenderInfo *sender_info = + g_array_index (packet->depends, + GibberRMulticastPacketSenderInfo *, n); + if (senders[i].sender_id == sender_info->sender_id) + { + fail_unless (senders[i].seen == FALSE); + fail_unless (senders[i].packet_id + 1 == sender_info->packet_id); + senders[i].seen = TRUE; + break; + } + } + fail_unless (senders[i].name != NULL); + } + + for (i = 0; senders[i].name != NULL ; i++) + { + fail_unless (senders[i].seen, "Not all senders in depends"); + } + + g_main_loop_quit (loop); +out: + g_object_unref (packet); + return TRUE; +} + +static gboolean +depends_send_test_data (gpointer data) +{ + GibberRMulticastCausalTransport *t = + GIBBER_R_MULTICAST_CAUSAL_TRANSPORT (data); + guint8 testdata[] = { 1, 2, 3 }; + + fail_unless (gibber_transport_send (GIBBER_TRANSPORT (t), testdata, + 3, NULL)); + + return FALSE; +} + +static void +depends_connected (GibberTransport *transport, + gpointer user_data) +{ + GibberRMulticastCausalTransport *rmctransport + = GIBBER_R_MULTICAST_CAUSAL_TRANSPORT (transport); + TestTransport *testtransport = TEST_TRANSPORT (user_data); + int i; + + /* First input some data packets, so the transport is forced to generate + * dependency info */ + for (i = 0 ; senders[i].name != NULL; i++) + { + GibberRMulticastPacket *packet; + guint8 *data; + gsize size; + + packet = gibber_r_multicast_packet_new (PACKET_TYPE_DATA, + senders[i].sender_id, + GIBBER_TRANSPORT (testtransport)->max_packet_size); + + gibber_r_multicast_causal_transport_add_sender (rmctransport, + senders[i].sender_id); + gibber_r_multicast_causal_transport_update_sender_start (rmctransport, + senders[i].sender_id, senders[i].packet_id); + + gibber_r_multicast_packet_set_packet_id (packet, senders[i].packet_id); + gibber_r_multicast_packet_set_data_info (packet, 0, 0, 1); + + data = gibber_r_multicast_packet_get_raw_data (packet, &size); + test_transport_write (testtransport, data, size); + g_object_unref (packet); + } + + /* Wait more then 200 ms, so all senders can get go to running */ + g_timeout_add (300, depends_send_test_data, rmctransport); +} + +START_TEST (test_depends) +{ + GibberRMulticastCausalTransport *rmctransport; + TestTransport *testtransport; + int i; + + loop = g_main_loop_new (NULL, FALSE); + + rmctransport = create_rmulticast_transport (&testtransport, "test123", + depends_send_hook, NULL); + + g_signal_connect (rmctransport, "connected", + G_CALLBACK (depends_connected), testtransport); + + rmulticast_connect (rmctransport); + + g_main_loop_run (loop); + g_main_loop_unref (loop); + + for (i = 0 ; senders[i].name != NULL; i++) + { + fail_unless (senders[i].seen); + } + + g_object_unref (rmctransport); +} +END_TEST + + +/* test fragmentation testing */ +static gboolean +fragmentation_send_hook (GibberTransport *transport, + const guint8 *data, + gsize length, + GError **error, + gpointer user_data) +{ + GibberRMulticastPacket *packet; + static gsize bytes = 0; + static guint8 next_byte = 0; + gsize i; + gsize size; + guint8 *payload; + + packet = gibber_r_multicast_packet_parse (data, length, NULL); + fail_unless (packet != NULL); + + if (packet->type != PACKET_TYPE_DATA) + { + goto out; + } + + payload = gibber_r_multicast_packet_get_payload (packet, &size); + + if (bytes == 0) + fail_unless + (packet->data.data.flags == GIBBER_R_MULTICAST_DATA_PACKET_START); + else if (bytes + size < TEST_DATA_SIZE) + fail_unless (packet->data.data.flags == 0); + + bytes += size; + fail_unless (bytes <= TEST_DATA_SIZE); + + /* check our bytes */ + for (i = 0; i < size; i++) + { + fail_unless (payload[i] == next_byte); + next_byte++; + } + + if (bytes == TEST_DATA_SIZE) + { + fail_unless + (packet->data.data.flags == GIBBER_R_MULTICAST_DATA_PACKET_END); + g_object_unref (packet); + g_main_loop_quit (loop); + return FALSE; + } + +out: + g_object_unref (packet); + return TRUE; +} + +static void +fragmentation_connected (GibberTransport *transport, + gpointer user_data) +{ + GibberRMulticastCausalTransport *rmctransport + = GIBBER_R_MULTICAST_CAUSAL_TRANSPORT (transport); + guint8 testdata[TEST_DATA_SIZE]; + int i; + + for (i = 0; i < TEST_DATA_SIZE; i++) + { + testdata[i] = (guint8) (i & 0xff); + } + + fail_unless (gibber_transport_send (GIBBER_TRANSPORT (rmctransport), + (guint8 *) testdata, TEST_DATA_SIZE, NULL)); +} + +START_TEST (test_fragmentation) +{ + GibberRMulticastCausalTransport *rmctransport; + + loop = g_main_loop_new (NULL, FALSE); + + rmctransport = create_rmulticast_transport (NULL, "test123", + fragmentation_send_hook, NULL); + + g_signal_connect (rmctransport, "connected", + G_CALLBACK (fragmentation_connected), NULL); + + rmulticast_connect (rmctransport); + + g_main_loop_run (loop); + g_main_loop_unref (loop); + + g_object_unref (rmctransport); +} +END_TEST + + +/* test unique id */ +static gboolean +unique_id_send_hook (GibberTransport *transport, + const guint8 *data, + gsize length, + GError **error, + gpointer user_data) +{ + GibberRMulticastPacket *packet; + guint32 *test_id = (guint32 *) user_data; + + + packet = gibber_r_multicast_packet_parse (data, length, NULL); + fail_unless (packet != NULL); + + if (*test_id == 0) + { + /* force collision */ + GibberRMulticastPacket *reply; + guint8 *pdata; + gsize psize; + + /* First packet must be a whois request to see if the id is taken */ + fail_unless (packet->type == PACKET_TYPE_WHOIS_REQUEST); + /* Sender must be 0 as it couldn't choose a id just yet */ + fail_unless (packet->sender == 0); + + *test_id = packet->data.whois_request.sender_id; + + reply = gibber_r_multicast_packet_new (PACKET_TYPE_WHOIS_REPLY, + *test_id, transport->max_packet_size); + + gibber_r_multicast_packet_set_whois_reply_info (reply, "romeo"); + + pdata = gibber_r_multicast_packet_get_raw_data (reply, &psize); + test_transport_write (TEST_TRANSPORT(transport), pdata, psize); + g_object_unref (reply); + } + else + { + fail_unless (*test_id != packet->sender); + switch (packet->type) + { + case PACKET_TYPE_WHOIS_REQUEST: + fail_unless (*test_id != packet->data.whois_request.sender_id); + break; + case PACKET_TYPE_WHOIS_REPLY: + /* transport sends a unsolicited whois reply after choosing a + * identifier */ + g_main_loop_quit (loop); + break; + default: + fail ("Unexpected packet type: %x", packet->type); + } + } + + g_object_unref (packet); + return TRUE; +} + +START_TEST (test_unique_id) +{ + /* Test if the multicast transport correctly handles the case that it gets a + * WHOIS_REPLY on one of it's WHOIS_REQUESTS when it's determining a unique + * id for itself */ + GibberRMulticastCausalTransport *rmctransport; + guint32 test_id; + + test_id = 0; + loop = g_main_loop_new (NULL, FALSE); + + rmctransport = create_rmulticast_transport (NULL, "test123", + unique_id_send_hook, &test_id); + + rmulticast_connect (rmctransport); + + g_main_loop_run (loop); + g_main_loop_unref (loop); + + g_object_unref (rmctransport); +} +END_TEST + +/* test id generation conflict */ +typedef struct { + guint32 id; + gint count; + gint wait; +} unique_id_conflict_test_t; + +static gboolean +id_generation_conflict_send_hook (GibberTransport *transport, + const guint8 *data, + gsize length, + GError **error, + gpointer user_data) +{ + GibberRMulticastPacket *packet; + unique_id_conflict_test_t *test = (unique_id_conflict_test_t *) user_data; + + packet = gibber_r_multicast_packet_parse (data, length, NULL); + fail_unless (packet != NULL); + + if (test->id == 0) + { + /* First packet must be a whois request to see if the id is taken */ + fail_unless (packet->type == PACKET_TYPE_WHOIS_REQUEST); + /* Sender must be 0 as it couldn't choose a id just yet */ + fail_unless (packet->sender == 0); + + test->id = packet->data.whois_request.sender_id; + } + + switch (packet->type) + { + case PACKET_TYPE_WHOIS_REQUEST: + test->count++; + + if (test->count < test->wait) + { + fail_unless (test->id == packet->data.whois_request.sender_id); + } + else if (test->count == test->wait) + { + /* force collision */ + GibberRMulticastPacket *reply; + guint8 *pdata; + gsize psize; + + fail_unless (test->id == packet->data.whois_request.sender_id); + + reply = gibber_r_multicast_packet_new (PACKET_TYPE_WHOIS_REQUEST, + 0, transport->max_packet_size); + + gibber_r_multicast_packet_set_whois_request_info (reply, test->id); + + pdata = gibber_r_multicast_packet_get_raw_data (reply, &psize); + test_transport_write (TEST_TRANSPORT(transport), pdata, psize); + g_object_unref (reply); + } + else if (test->count > test->wait) + { + fail_unless (test->id != packet->data.whois_request.sender_id); + } + + break; + + case PACKET_TYPE_WHOIS_REPLY: + /* transport sends a unsolicited whois reply after choosing a + * identifier */ + fail_unless (packet->sender != test->id); + fail_unless (test->count == + ID_GENERATION_EXPECTED_POLLS + test->wait); + g_main_loop_quit (loop); + break; + + default: + fail ("Unexpected packet type: %x", packet->type); + } + + g_object_unref (packet); + return TRUE; +} + +START_TEST (test_id_generation_conflict) +{ + /* Test if the multicast transport correctly handles the case that it sees + * another WHOIS_REQUEST on one of its WHOIS_REQUESTS when it's determining + * a unique id for itself */ + GibberRMulticastCausalTransport *rmtransport; + unique_id_conflict_test_t test; + + test.id = 0; + test.count = 0; + test.wait = _i + 1; + + loop = g_main_loop_new (NULL, FALSE); + + rmtransport = create_rmulticast_transport (NULL, "test123", + id_generation_conflict_send_hook, &test); + + rmulticast_connect (rmtransport); + + g_main_loop_run (loop); + g_main_loop_unref (loop); + + g_object_unref (rmtransport); +} +END_TEST + + +TCase * +make_gibber_r_multicast_causal_transport_tcase (void) +{ + TCase *tc = tcase_create ("Gibber R Multicast Causal transport"); + tcase_add_test (tc, test_unique_id); + tcase_add_loop_test (tc, test_id_generation_conflict, 0, + ID_GENERATION_EXPECTED_POLLS); + tcase_add_test (tc, test_fragmentation); + tcase_add_test (tc, test_depends); + + return tc; +} diff --git a/lib/gibber/tests/check-gibber-r-multicast-packet.c b/lib/gibber/tests/check-gibber-r-multicast-packet.c new file mode 100644 index 00000000..52bfef41 --- /dev/null +++ b/lib/gibber/tests/check-gibber-r-multicast-packet.c @@ -0,0 +1,228 @@ +#include <stdio.h> +#include <string.h> + +#include <gibber/gibber-r-multicast-packet.h> + +#include <check.h> +#include "check-gibber.h" + +#define COMPARE(x) G_STMT_START { \ + fail_unless (a->x == b->x); \ +} G_STMT_END + +typedef struct { + guint32 sender_id; + guint32 packet_id; + gboolean seen; +} sender_t; + +typedef struct { + guint32 a; + guint32 b; + gint32 result; +} diff_testcase; + +#define NUMBER_OF_DIFF_TESTS 15 + +START_TEST (test_r_multicast_packet_diff) +{ + diff_testcase cases[NUMBER_OF_DIFF_TESTS] = + { { 0, 0, 0 }, + { 10, 10, 0 }, + { 5, 10, 5 }, + { 10, 5, -5 }, + { G_MAXUINT32 - 10, 10, 21 }, + { G_MAXUINT32, 0, 1 }, + { 0 , G_MAXUINT32, -1 }, + { G_MAXUINT32, 10, 11 }, + { 10, G_MAXUINT32, -11 }, + { G_MAXUINT32/2, G_MAXUINT32, G_MAXINT32 }, + { G_MAXUINT32, G_MAXUINT32/2, -G_MAXINT32 }, + { G_MAXUINT32/2 - 1, G_MAXUINT32, G_MAXINT32 }, + { G_MAXUINT32, G_MAXUINT32/2 - 1, -G_MAXINT32 }, + { G_MAXUINT32 - 5, 5, 11 }, + { 5, G_MAXUINT32 - 5, -11 }, + + }; + + diff_testcase *c = cases + _i; + gint32 result = gibber_r_multicast_packet_diff (c->a, c->b); + fail_unless (c->result == result); +} +END_TEST + +START_TEST (test_data_packet) +{ + GibberRMulticastPacket *a; + GibberRMulticastPacket *b; + guint32 sender_id = 1234; + guint32 packet_id = 1200; + guint8 flags = GIBBER_R_MULTICAST_DATA_PACKET_START; + guint32 total_size = 800; + guint16 stream_id = 56; + guint8 *data; + gsize len; + guint8 *pdata; + gsize plen; + guint i,n; + sender_t senders[] = + { { 0x300, 500, FALSE }, { 0x400, 600, FALSE }, { 0, 0, FALSE } }; + gchar *payload = "1234567890"; + + g_type_init (); + + a = gibber_r_multicast_packet_new (PACKET_TYPE_DATA, sender_id, 1500); + gibber_r_multicast_packet_set_packet_id (a, packet_id); + gibber_r_multicast_packet_set_data_info (a, stream_id, flags, total_size); + + for (i = 0 ; senders[i].sender_id != 0; i++) + { + gibber_r_multicast_packet_add_sender_info (a, + senders[i].sender_id, senders[i].packet_id, NULL); + } + + gibber_r_multicast_packet_add_payload (a, (guint8 *) payload, + strlen (payload)); + + data = gibber_r_multicast_packet_get_raw_data (a, &len); + + b = gibber_r_multicast_packet_parse (data, len, NULL); + fail_unless (b != NULL); + + COMPARE (type); + COMPARE (version); + COMPARE (data.data.flags); + COMPARE (data.data.total_size); + COMPARE (packet_id); + COMPARE (data.data.stream_id); + + fail_unless (a->sender == b->sender); + + for (n = 0 ; n < b->depends->len; n++) + { + for (i = 0; senders[i].sender_id != 0 ; i++) + { + GibberRMulticastPacketSenderInfo *s = g_array_index (b->depends, + GibberRMulticastPacketSenderInfo *, n); + if (senders[i].sender_id == s->sender_id) + { + fail_unless (senders[i].packet_id == s->packet_id); + fail_unless (senders[i].seen == FALSE); + senders[i].seen = TRUE; + break; + } + } + + fail_unless (senders[i].sender_id != 0); + } + + for (i = 0; senders[i].sender_id != 0 ; i++) + { + fail_unless (senders[i].seen == TRUE); + } + + + pdata = gibber_r_multicast_packet_get_payload (b, &plen); + fail_unless (plen == strlen (payload)); + + fail_unless (memcmp (payload, pdata, plen) == 0); + + g_object_unref (a); + g_object_unref (b); +} END_TEST + +START_TEST (test_attempt_join_packet) +{ + GibberRMulticastPacket *a; + GibberRMulticastPacket *b; + guint32 sender_id = 1234; + guint32 packet_id = 1200; + guint8 *data; + gsize len; + guint i, n; + sender_t senders[] = + { { 0x300, 500, FALSE }, { 0x400, 600, FALSE }, { 0, 0, FALSE } }; + sender_t new_senders[] = + { { 0x500, 0, FALSE }, { 0x600, 0, FALSE }, { 0, 0, FALSE } }; + + g_type_init (); + + a = gibber_r_multicast_packet_new (PACKET_TYPE_ATTEMPT_JOIN, + sender_id, 1500); + gibber_r_multicast_packet_set_packet_id (a, packet_id); + + for (i = 0; senders[i].sender_id != 0; i++) + { + gibber_r_multicast_packet_add_sender_info (a, + senders[i].sender_id, senders[i].packet_id, NULL); + } + for (i = 0; new_senders[i].sender_id != 0; i++) + { + gibber_r_multicast_packet_attempt_join_add_sender (a, + new_senders[i].sender_id, NULL); + } + + data = gibber_r_multicast_packet_get_raw_data (a, &len); + + b = gibber_r_multicast_packet_parse (data, len, NULL); + + fail_unless (b != NULL); + + COMPARE (type); + COMPARE (version); + COMPARE (packet_id); + COMPARE (data.attempt_join.senders->len); + + fail_unless (a->sender == b->sender); + + for (n = 0; n < b->depends->len; n++) + { + for (i = 0; senders[i].sender_id != 0 ; i++) + { + GibberRMulticastPacketSenderInfo *s = g_array_index (b->depends, + GibberRMulticastPacketSenderInfo *, n); + if (senders[i].sender_id == s->sender_id) + { + fail_unless (senders[i].packet_id == s->packet_id); + fail_unless (senders[i].seen == FALSE); + senders[i].seen = TRUE; + break; + } + } + + fail_unless (senders[i].sender_id != 0); + } + + for (i = 0; senders[i].sender_id != 0; i++) + { + fail_unless (senders[i].seen == TRUE); + } + + for (i = 0; new_senders[i].sender_id != 0; i++) + { + fail_unless (new_senders[i].sender_id == + g_array_index (b->data.attempt_join.senders, guint32, i)); + new_senders[i].seen = TRUE; + break; + } + + for (i = 0; new_senders[i].sender_id != 0; i++) + { + fail_unless (senders[i].seen == TRUE); + } + + g_object_unref (a); + g_object_unref (b); +} +END_TEST + +TCase * +make_gibber_r_multicast_packet_tcase (void) +{ + TCase *tc = tcase_create ("RMulticast Packet"); + tcase_add_test (tc, test_data_packet); + tcase_add_test (tc, test_attempt_join_packet); + tcase_add_loop_test (tc, test_r_multicast_packet_diff, 0, + NUMBER_OF_DIFF_TESTS); + return tc; +} diff --git a/lib/gibber/tests/check-gibber-r-multicast-sender.c b/lib/gibber/tests/check-gibber-r-multicast-sender.c new file mode 100644 index 00000000..b0a4c903 --- /dev/null +++ b/lib/gibber/tests/check-gibber-r-multicast-sender.c @@ -0,0 +1,652 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <gibber/gibber-r-multicast-sender.h> + +#include <check.h> +#include "check-gibber.h" + +#define SENDER 4321 +#define SENDER_NAME "testsender" + +#define REPAIR_PACKET ((guint32)15) + +#define EXTRA_SEEN ((guint32)11) +#define NR_PACKETS ((guint32)40) + +guint32 serial_offset; +guint32 expected; + +typedef struct { + guint32 serial_offset; + gboolean test_seen; +} test_t; + +typedef struct { + guint32 receiver_id; + const gchar *name; + guint32 packet_id; +} recv_t; + +GMainLoop *loop; +recv_t receivers[] = { + { 0x500, "sender1", 500 }, + { 0x600, "sender2", 600 }, + { 0, NULL, 0 } +}; + +static GibberRMulticastPacket * +generate_packet (guint32 serial) +{ + GibberRMulticastPacket *p; + guint8 flags = 0; + gint total = 1; + gchar *payload; + guint8 stream_id = 0; + int i; + + switch (serial % 3) + { + case 0: + flags = GIBBER_R_MULTICAST_DATA_PACKET_START + | GIBBER_R_MULTICAST_DATA_PACKET_END; + stream_id = serial % G_MAXUINT8; + break; + case 1: + flags = GIBBER_R_MULTICAST_DATA_PACKET_START; + stream_id = serial % G_MAXUINT8; + total = 2; + break; + case 2: + flags = GIBBER_R_MULTICAST_DATA_PACKET_END; + stream_id = (serial - 1) % G_MAXUINT8; + total = 2; + break; + } + + p = gibber_r_multicast_packet_new (PACKET_TYPE_DATA, SENDER, 1500); + + gibber_r_multicast_packet_set_packet_id (p, serial); + gibber_r_multicast_packet_set_data_info (p, stream_id, flags, total * 11); + + for (i = 0 ; receivers[i].receiver_id != 0; i++) + { + gibber_r_multicast_packet_add_sender_info (p, + receivers[i].receiver_id, receivers[i].packet_id, NULL); + } + + payload = g_strdup_printf ("%010d\n", serial); + gibber_r_multicast_packet_add_payload (p, (guint8 *) payload, + strlen (payload)); + + g_free (payload); + return p; +} + +static void +data_received_cb (GibberRMulticastSender *sender, guint8 stream_id, + guint8 *data, gsize size, gpointer user_data) +{ + gchar *str; + gchar **lines; + int i; + + str = g_strndup ((const gchar *)data, size); + + lines = g_strsplit (str, "\n", 0); + for (i = 0 ; lines[i] != NULL && *lines[i] != '\0'; i++) { + guint32 v = atoi (lines[i]); + + fail_unless (v == expected); + fail_unless ((v % G_MAXUINT8) - i == stream_id); + expected++; + } + /* serial % 3 is send out in a single packet the other two together. + * So expected can't be % 3 == 2 here */ + fail_if (expected % 3 == 2); + + if (expected == serial_offset + NR_PACKETS + || expected == serial_offset + NR_PACKETS + EXTRA_SEEN) { + g_main_loop_quit ((GMainLoop *) user_data); + } + + g_strfreev (lines); + g_free (str); + +} + +static void +repair_request_cb (GibberRMulticastSender *sender, guint id, gpointer data) +{ + GibberRMulticastPacket *p; + + fail_unless (gibber_r_multicast_packet_diff (serial_offset, id) >= 0 + || gibber_r_multicast_packet_diff (id, + serial_offset + NR_PACKETS + EXTRA_SEEN) < 0); + + p = generate_packet (id); + gibber_r_multicast_sender_push (sender, p); + g_object_unref (p); +} + +static void +repair_message_cb (GibberRMulticastSender *sender, + GibberRMulticastPacket *packet, gpointer user_data) +{ + + fail_unless (packet->type == PACKET_TYPE_DATA); + fail_unless (packet->packet_id == REPAIR_PACKET + serial_offset); + + g_main_loop_quit ((GMainLoop *) user_data); +} + +static gboolean +add_packet (gpointer data) +{ + static guint32 i = 0; + GibberRMulticastSender *sender = GIBBER_R_MULTICAST_SENDER (data); + GibberRMulticastPacket *p; + + if (i == NR_PACKETS) + { + i = 0; + return FALSE; + } + + if (i % 5 != 3) + { + p = generate_packet (i + serial_offset); + gibber_r_multicast_sender_push (sender, p); + g_object_unref (p); + } + + i++; + return TRUE; +} + + +#define NUMBER_OF_TESTS 3 + +START_TEST (test_sender) +{ + GibberRMulticastSender *s; + GibberRMulticastSenderGroup *group; + test_t tests[NUMBER_OF_TESTS] = { + { (guint32)(~0 - NR_PACKETS/2), TRUE }, + { 0xff, TRUE }, + { 0xff, FALSE }, + }; + int i; + + g_type_init (); + group = gibber_r_multicast_sender_group_new (); + loop = g_main_loop_new (NULL, FALSE); + + serial_offset = tests[_i].serial_offset; + expected = serial_offset; + + for (i = 0 ; receivers[i].receiver_id != 0; i++) + { + s = gibber_r_multicast_sender_new (receivers[i].receiver_id, + receivers[i].name, group); + gibber_r_multicast_sender_update_start (s, receivers[i].packet_id); + gibber_r_multicast_sender_seen (s, receivers[i].packet_id + 1); + gibber_r_multicast_sender_group_add (group, s); + } + + s = gibber_r_multicast_sender_new (SENDER, SENDER_NAME, group); + g_signal_connect (s, "received-data", G_CALLBACK(data_received_cb), loop); + g_signal_connect (s, "repair-request", G_CALLBACK(repair_request_cb), loop); + + gibber_r_multicast_sender_update_start (s, serial_offset); + gibber_r_multicast_sender_set_data_start (s, serial_offset); + + if (tests[_i].test_seen) + { + gibber_r_multicast_sender_seen (s, serial_offset); + } + else + { + gibber_r_multicast_sender_repair_request (s, serial_offset); + } + + g_timeout_add (10, add_packet, s); + + g_main_loop_run (loop); + + /* tell the sender we've seen some extra pakcets */ + gibber_r_multicast_sender_seen (s, serial_offset + NR_PACKETS + EXTRA_SEEN); + g_main_loop_run (loop); + + /* Ask for a repair */ + g_signal_connect (s, "repair-message", G_CALLBACK (repair_message_cb), loop); + + gibber_r_multicast_sender_repair_request (s, serial_offset + REPAIR_PACKET); + + g_main_loop_run (loop); + + gibber_r_multicast_sender_group_free (group); +} END_TEST + +/* Holding test */ +guint32 idle_timer = 0; + +typedef struct { + gchar *name; + guint32 packet_id; + GibberRMulticastPacketType packet_type; + gchar *data; + gchar *depend_node; + guint32 depend_packet_id; + guint16 data_stream_id; + guint8 flags; + guint32 total_size; +} h_setup_t; + +typedef enum { + EXPECT = 0, + START_DATA, + FAIL, + HOLD, + UNHOLD, + UNHOLD_IMMEDIATE, + DONE +} h_expect_type_t; + +typedef struct { + h_expect_type_t type; + gchar *expected_node; + GibberRMulticastPacketType packet_type; + guint32 hold_id; + guint32 data_stream_id; +} h_expect_t; + +typedef struct { + int test_step; + GibberRMulticastSenderGroup *group; + h_expect_t *expectation; +} h_data_t; + +typedef struct { + h_setup_t *setup; + h_expect_t *expectation; +} h_test_t; + +static void h_next_test_step (h_data_t *d); + +static gboolean +h_find_sender (gpointer key, gpointer value, gpointer user_data) +{ + GibberRMulticastSender *s = GIBBER_R_MULTICAST_SENDER (value); + + return strcmp (s->name, (gchar *) user_data) == 0; +} + +static gboolean +h_idle_next_step (gpointer user_data) +{ + h_data_t *d = (h_data_t *) user_data; + h_expect_t *e = &(d->expectation[d->test_step]); + GibberRMulticastSender *s; + + idle_timer = 0; + + switch (e->type) { + case UNHOLD_IMMEDIATE: + case START_DATA: + case FAIL: + case EXPECT: + fail ("Should not be reached"); + break; + case HOLD: + s = g_hash_table_find (d->group->senders, + h_find_sender, e->expected_node); + fail_unless (s != NULL); + d->test_step++; + gibber_r_multicast_sender_hold_data (s, e->hold_id); + h_next_test_step (d); + break; + case UNHOLD: + s = g_hash_table_find (d->group->senders, + h_find_sender, e->expected_node); + fail_unless (s != NULL); + d->test_step++; + gibber_r_multicast_sender_release_data (s); + h_next_test_step (d); + break; + case DONE: + /* And there was great rejoice */ + g_main_loop_quit (loop); + break; + } + + return FALSE; +} + +static void +h_next_test_step (h_data_t *d) +{ + GibberRMulticastSender *s; + h_expect_t *e = &(d->expectation[d->test_step]); + + switch (d->expectation[d->test_step].type) { + case EXPECT: + break; + case UNHOLD_IMMEDIATE: + s = g_hash_table_find (d->group->senders, + h_find_sender, e->expected_node); + fail_unless (s != NULL); + d->test_step++; + gibber_r_multicast_sender_release_data (s); + h_next_test_step (d); + break; + case START_DATA: + s = g_hash_table_find (d->group->senders, + h_find_sender, e->expected_node); + fail_unless (s != NULL); + d->test_step++; + gibber_r_multicast_sender_set_data_start (s, e->hold_id); + h_next_test_step (d); + break; + case FAIL: + s = g_hash_table_find (d->group->senders, + h_find_sender, e->expected_node); + fail_unless (s != NULL); + d->test_step++; + gibber_r_multicast_sender_set_failed (s); + h_next_test_step (d); + break; + case HOLD: + case UNHOLD: + case DONE: + if (idle_timer == 0) + { + idle_timer = g_idle_add (h_idle_next_step, d); + } + } +} + +static void +h_received_data_cb (GibberRMulticastSender *sender, guint16 stream_id, + guint8 *data, gsize size, gpointer user_data) +{ + h_data_t *d = (h_data_t *) user_data; + + fail_unless (d->expectation[d->test_step].type == EXPECT); + fail_unless (d->expectation[d->test_step].packet_type == PACKET_TYPE_DATA); + fail_unless ( + strcmp (d->expectation[d->test_step].expected_node, sender->name) == 0); + fail_unless (d->expectation[d->test_step].data_stream_id == stream_id); + + d->test_step++; + h_next_test_step (d); +} + +static void +h_received_control_packet_cb (GibberRMulticastSender *sender, + GibberRMulticastPacket *packet, gpointer user_data) +{ + h_data_t *d = (h_data_t *) user_data; + + fail_unless (d->expectation[d->test_step].type == EXPECT); + fail_unless (d->expectation[d->test_step].packet_type == packet->type); + fail_unless ( + strcmp (d->expectation[d->test_step].expected_node, sender->name) == 0); + + d->test_step++; + h_next_test_step (d); +} + +h_setup_t h_setup0[] = { + { "node0", 0x1, PACKET_TYPE_DATA, "001", NULL, 0x0, 0, 3, 3 }, + { "node1", 0x1, PACKET_TYPE_DATA, "001", "node0", 0x2, 0, 3, 3 }, + { "node0", 0x2, PACKET_TYPE_DATA, "002", "node1", 0x2, 0, 3, 3 }, + { "node1", 0x2, PACKET_TYPE_DATA, "002", "node0", 0x3, 0, 3, 3 }, + { "node0", 0x3, PACKET_TYPE_ATTEMPT_JOIN, NULL, "node1", 0x3 }, + { "node1", 0x3, PACKET_TYPE_ATTEMPT_JOIN, NULL, "node0", 0x4 }, + { "node0", 0x4, PACKET_TYPE_DATA, "003", "node1", 0x4, 0, 3, 3 }, + { "node1", 0x4, PACKET_TYPE_DATA, "003", "node0", 0x5, 0, 3, 3 }, + { "node0", 0x5, PACKET_TYPE_JOIN, NULL, "node1", 0x5 }, + { "node1", 0x5, PACKET_TYPE_JOIN, NULL, "node0", 0x6 }, + { NULL }, + }; + +h_expect_t h_expectation0[] = { + { EXPECT, "node0", PACKET_TYPE_ATTEMPT_JOIN }, + { EXPECT, "node1", PACKET_TYPE_ATTEMPT_JOIN }, + { EXPECT, "node0", PACKET_TYPE_JOIN }, + { EXPECT, "node1", PACKET_TYPE_JOIN }, + /* Set the data start of node1 to 0x1, which means all the data should still + * be popped off */ + { START_DATA, "node1", PACKET_TYPE_INVALID, 0x1 }, + { START_DATA, "node0", PACKET_TYPE_INVALID, 0x1 }, + /* only unhold node1, nothing should happen as they depend on those of + * node0 */ + { HOLD, "node1", PACKET_TYPE_INVALID, 0x3 }, + /* unhold node0 too, packets should start flowing */ + { HOLD, "node0", PACKET_TYPE_INVALID, 0x3 }, + { EXPECT, "node0", PACKET_TYPE_DATA, 0, 0 }, + { EXPECT, "node1", PACKET_TYPE_DATA, 0, 0 }, + { EXPECT, "node0", PACKET_TYPE_DATA, 0, 0 }, + { EXPECT, "node1", PACKET_TYPE_DATA, 0, 0 }, + { UNHOLD, "node1" }, + { UNHOLD, "node0" }, + { EXPECT, "node0", PACKET_TYPE_DATA, 0, 0 }, + { EXPECT, "node1", PACKET_TYPE_DATA, 0, 0 }, + { DONE }, +}; + +h_setup_t h_setup1[] = { + { "node0", 0x1, PACKET_TYPE_ATTEMPT_JOIN, "001", "node1", 0x2 }, + { "node1", 0x1, PACKET_TYPE_ATTEMPT_JOIN, "001", NULL }, + { NULL }, +}; + +h_expect_t h_expectation1[] = { + { EXPECT, "node1", PACKET_TYPE_ATTEMPT_JOIN }, + { EXPECT, "node0", PACKET_TYPE_ATTEMPT_JOIN }, + { DONE } +}; + +h_setup_t h_setup2[] = { + { "node0", 0x1, PACKET_TYPE_DATA, "001", NULL, 0x0, 0, 1, 9 }, + { "node0", 0x3, PACKET_TYPE_DATA, "001", NULL, 0x0, 0, 0, 9 }, + { "node0", 0x6, PACKET_TYPE_DATA, "001", NULL, 0x0, 0, 2, 9 }, + { "node0", 0x2, PACKET_TYPE_DATA, "001", NULL, 0x0, 1, 1, 6 }, + { "node0", 0x4, PACKET_TYPE_DATA, "001", NULL, 0x0, 2, 3, 3 }, + { "node0", 0x5, PACKET_TYPE_DATA, "001", NULL, 0x0, 1, 2, 6 }, + { NULL }, +}; + +h_expect_t h_expectation2[] = { + { START_DATA, "node0", PACKET_TYPE_INVALID, 0x1 }, + { UNHOLD, "node0" }, + { EXPECT, "node0", PACKET_TYPE_DATA, 0, 2 }, + { EXPECT, "node0", PACKET_TYPE_DATA, 0, 1 }, + { EXPECT, "node0", PACKET_TYPE_DATA, 0, 0 }, + { DONE } +}; + +h_setup_t h_setup3[] = { + { "node0", 0x1, PACKET_TYPE_DATA, "001", NULL, 0x0, 0, 1, 9 }, + { "node0", 0x2, PACKET_TYPE_DATA, "001", NULL, 0x0, 1, 1, 6 }, + { "node0", 0x3, PACKET_TYPE_ATTEMPT_JOIN, NULL, NULL }, + { "node0", 0x4, PACKET_TYPE_DATA, "001", NULL, 0x0, 0, 0, 9 }, + { "node0", 0x5, PACKET_TYPE_DATA, "001", NULL, 0x0, 2, 3, 3 }, + { "node0", 0x6, PACKET_TYPE_DATA, "001", NULL, 0x0, 1, 2, 6 }, + { "node0", 0x7, PACKET_TYPE_ATTEMPT_JOIN, NULL, NULL }, + { "node0", 0x8, PACKET_TYPE_DATA, "001", NULL, 0x0, 0, 2, 9 }, + { NULL }, +}; + +h_expect_t h_expectation3[] = { + { EXPECT, "node0", PACKET_TYPE_ATTEMPT_JOIN }, + { START_DATA, "node0", PACKET_TYPE_INVALID, 0x1 }, + { UNHOLD_IMMEDIATE, "node0" }, + { EXPECT, "node0", PACKET_TYPE_DATA, 0, 2 }, + { EXPECT, "node0", PACKET_TYPE_DATA, 0, 1 }, + { EXPECT, "node0", PACKET_TYPE_ATTEMPT_JOIN }, + { EXPECT, "node0", PACKET_TYPE_DATA, 0, 0 }, + { DONE } +}; + +h_setup_t h_setup4[] = { + { "node0", 0x1, PACKET_TYPE_DATA, "001", NULL, 0x0, 0, 1, 9 }, + { "node0", 0x2, PACKET_TYPE_DATA, "001", NULL, 0x0, 1, 1, 6 }, + { "node0", 0x3, PACKET_TYPE_DATA, "001", NULL, 0x0, 0, 0, 9 }, + { "node0", 0x4, PACKET_TYPE_DATA, "001", NULL, 0x0, 2, 3, 3 }, + { "node0", 0x5, PACKET_TYPE_DATA, "001", NULL, 0x0, 1, 2, 6 }, + { "node0", 0x6, PACKET_TYPE_DATA, "001", NULL, 0x0, 0, 2, 9 }, + { NULL }, +}; + +h_expect_t h_expectation4[] = { + { START_DATA, "node0", PACKET_TYPE_INVALID, 0x2 }, + { UNHOLD, "node0" }, + { EXPECT, "node0", PACKET_TYPE_DATA, 0, 2 }, + { EXPECT, "node0", PACKET_TYPE_DATA, 0, 1 }, + { DONE } +}; + +/* Test if failing a node correctly pops the minimum amount of packets needed + * to fulfill all dependencies */ +h_setup_t h_setup5[] = { + { "node1", 0x1, PACKET_TYPE_DATA, "001", NULL, 0x0, 1, 3, 3 }, + { "node1", 0x2, PACKET_TYPE_DATA, "001", "node0", 0x3, 2, 3, 3 }, + + /* As the very first thing do a Control packet, which isn't hold back. To + * force the setting of FAIL (as the setup instructions are run as soon as + * the join packet is received) */ + { "node0", 0x1, PACKET_TYPE_JOIN, "001", NULL }, + { "node0", 0x2, PACKET_TYPE_DATA, "001", "node1", 0x2, 2, 3, 3 }, + { "node0", 0x3, PACKET_TYPE_DATA, "001", NULL, 0x0, 0, 3, 3 }, + { NULL }, +}; + +h_expect_t h_expectation5[] = { + { EXPECT, "node0", PACKET_TYPE_JOIN, 0, 1 }, + { START_DATA, "node0", PACKET_TYPE_INVALID, 0x1 }, + { START_DATA, "node1", PACKET_TYPE_INVALID, 0x1 }, + { FAIL, "node0", PACKET_TYPE_INVALID, 0x2 }, + { UNHOLD, "node0" }, + { UNHOLD, "node1" }, + { EXPECT, "node1", PACKET_TYPE_DATA, 0, 1 }, + { EXPECT, "node0", PACKET_TYPE_DATA, 0, 2 }, + { EXPECT, "node1", PACKET_TYPE_DATA, 0, 2 }, + { DONE } +}; + +#define NUMBER_OF_H_TESTS 6 +h_test_t h_tests[NUMBER_OF_H_TESTS] = { + { h_setup0, h_expectation0 }, + { h_setup1, h_expectation1 }, + { h_setup2, h_expectation2 }, + { h_setup3, h_expectation3 }, + { h_setup4, h_expectation4 }, + { h_setup5, h_expectation5 }, + }; + + +static void +add_h_sender (guint32 sender, gchar *name, GibberRMulticastSenderGroup *group, + guint32 packet_id, h_data_t *data) +{ + GibberRMulticastSender *s; + + s = gibber_r_multicast_sender_new (sender, name, group); + gibber_r_multicast_sender_update_start (s, packet_id); + gibber_r_multicast_sender_hold_data (s, packet_id); + gibber_r_multicast_sender_group_add (group, s); + + g_signal_connect (s, "received-data", + G_CALLBACK (h_received_data_cb), data); + g_signal_connect (s, "received-control-packet", + G_CALLBACK (h_received_control_packet_cb), data); +} + +START_TEST (test_holding) { + GibberRMulticastSenderGroup *group; + guint32 sender_offset = 0xf00; + /* control packets aren't hold back, thus we get them interleaved at first + */ + h_test_t *test = h_tests + _i; + h_data_t data = { 0, NULL, test->expectation }; + int i; + + g_type_init (); + loop = g_main_loop_new (NULL, FALSE); + + group = gibber_r_multicast_sender_group_new (); + data.group = group; + + for (i = 0; test->setup[i].name != NULL; i++) + { + GibberRMulticastSender *s; + s = g_hash_table_find (group->senders, + h_find_sender, test->setup[i].name); + if (s == NULL) + { + add_h_sender (sender_offset++, test->setup[i].name, group, + test->setup[i].packet_id, &data); + } + } + + for (i = 0; test->setup[i].name != NULL; i++) + { + GibberRMulticastSender *s0, *s1 = NULL; + GibberRMulticastPacket *p; + + s0 = g_hash_table_find (group->senders, h_find_sender, + test->setup[i].name); + fail_unless (s0 != NULL); + + p = gibber_r_multicast_packet_new (test->setup[i].packet_type, s0->id, + 1500); + gibber_r_multicast_packet_set_packet_id (p, test->setup[i].packet_id); + + if (test->setup[i].depend_node != NULL) + { + s1 = g_hash_table_find (group->senders, h_find_sender, + test->setup[i].depend_node); + fail_unless (s1 != NULL); + fail_unless (gibber_r_multicast_packet_add_sender_info (p, s1->id, + test->setup[i].depend_packet_id, NULL)); + } + if (test->setup[i].packet_type == PACKET_TYPE_DATA) + { + fail_unless (test->setup[i].data != NULL); + + gibber_r_multicast_packet_set_data_info (p, + test->setup[i].data_stream_id, + test->setup[i].flags, + test->setup[i].total_size); + gibber_r_multicast_packet_add_payload (p, + (guint8 *) test->setup[i].data, strlen (test->setup[i].data)); + } + gibber_r_multicast_sender_push (s0, p); + + g_object_unref (p); + } + + h_next_test_step (&data); + + do + { + g_main_loop_run (loop); + } + while (data.expectation[data.test_step].type != DONE); + + fail_unless (idle_timer == 0); + +} END_TEST + +TCase * +make_gibber_r_multicast_sender_tcase (void) +{ + TCase *tc = tcase_create ("RMulticast Sender"); + tcase_set_timeout (tc, 20); + tcase_add_loop_test (tc, test_sender, 0, NUMBER_OF_TESTS); + tcase_add_loop_test (tc, test_holding, 0, NUMBER_OF_H_TESTS ); + return tc; +} diff --git a/lib/gibber/tests/check-gibber-resolver.c b/lib/gibber/tests/check-gibber-resolver.c new file mode 100644 index 00000000..ba6effa0 --- /dev/null +++ b/lib/gibber/tests/check-gibber-resolver.c @@ -0,0 +1,91 @@ +/* + * check-gibber-resolver.c - Test for gibber-resolver functions + * Copyright (C) 2008 Collabora Ltd. + * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "test-resolver.h" +#include "check-gibber.h" + +#include <check.h> + +GMainLoop *mainloop = NULL; +gboolean done = FALSE; + +static void +resolver_srv_cb (GibberResolver *resolver, GList *srv_list, GError *error, + gpointer user_data, GObject *weak_object) +{ + GList *s; + int last_prio = 0; + int last_weight = 0; + + for (s = srv_list ; s != NULL; s = g_list_next (s)) + { + GibberResolverSrvRecord *r = (GibberResolverSrvRecord *) s->data; + + fail_unless (last_prio <= r->priority); + + if (last_prio != r->priority) + last_weight = 0; + + /* If our previous weight was non-zero, then this one has to be non-zero + * too. The SRV RFC requires all entries with zero weight to be sorted + * before all other entries with the same priority */ + fail_unless (last_weight == 0 || r->weight != 0); + + last_prio = r->priority; + last_weight = r->weight; + } + + done = TRUE; + + if (g_main_loop_is_running (mainloop)) + g_main_loop_quit (mainloop); +} + +START_TEST (test_srv_resolving) +{ + GibberResolver *resolver; + + done = FALSE; + mainloop = g_main_loop_new (NULL, FALSE); + + resolver = g_object_new (TEST_TYPE_RESOLVER, NULL); + + gibber_resolver_srv (resolver, "test", "test", + GIBBER_RESOLVER_SERVICE_TYPE_TCP, + resolver_srv_cb, NULL, NULL, NULL); + + if (!done) + g_main_loop_run (mainloop); + + g_main_loop_unref (mainloop); +} END_TEST + +TCase * +make_gibber_resolver_tcase (void) +{ + TCase *tc = tcase_create ("Resolve"); + tcase_add_test (tc, test_srv_resolving); + return tc; +} diff --git a/lib/gibber/tests/check-gibber-sasl-auth.c b/lib/gibber/tests/check-gibber-sasl-auth.c new file mode 100644 index 00000000..4ce68ff3 --- /dev/null +++ b/lib/gibber/tests/check-gibber-sasl-auth.c @@ -0,0 +1,213 @@ +#include <stdio.h> + +#include "test-sasl-auth-server.h" +#include "test-transport.h" +#include <gibber/gibber-xmpp-connection.h> +#include <gibber/gibber-sasl-auth.h> + +#include <check.h> +#include "check-gibber.h" + +typedef struct { + gchar *description; + gchar *mech; + gboolean allow_plain; + GQuark domain; + int code; + ServerProblem problem; +} test_t; + +GMainLoop *mainloop; +GibberTransport *servertransport; +GibberTransport *clienttransport; +GibberXmppConnection *conn; +GibberSaslAuth *sasl = NULL; + +const gchar *username = "test"; +const gchar *password = "test123"; +const gchar *servername = "testserver"; + +gboolean authenticated = FALSE; +gboolean run_done = FALSE; + +test_t *current_test = NULL; +GError *error = NULL; + +static void +got_error (GQuark domain, int code, const gchar *message) +{ + g_set_error (&error, domain, code, "%s", message); + run_done = TRUE; + g_main_loop_quit (mainloop); +} + +static gboolean +send_hook (GibberTransport *transport, const guint8 *data, + gsize length, GError **err, gpointer user_data) +{ + GibberTransport *target = + (servertransport == transport) ? clienttransport : servertransport; + + test_transport_write (TEST_TRANSPORT (target), data, length); + return TRUE; +} + +static gchar * +return_str (GibberSaslAuth *auth, gpointer user_data) +{ + return g_strdup (user_data); +} + +static void +auth_success (GibberSaslAuth *sasl_, gpointer user_data) +{ + authenticated = TRUE; + /* Reopen the connection */ + gibber_xmpp_connection_restart (conn); + gibber_xmpp_connection_open (conn, servername, NULL, "1.0"); +} + +static void +auth_failed (GibberSaslAuth *sasl_, GQuark domain, + int code, gchar *message, gpointer user_data) +{ + got_error (domain, code, message); +} + +static void +parse_error (GibberXmppConnection *connection, gpointer user_data) +{ + fail (); +} + +static void +stream_opened (GibberXmppConnection *connection, + gchar *from, gchar *to, gchar *version, gpointer user_data) +{ + if (authenticated) + gibber_xmpp_connection_close (conn); +} + +static void +stream_closed (GibberXmppConnection *connection, gpointer user_data) +{ + run_done = TRUE; + g_main_loop_quit (mainloop); +} + +static void +received_stanza (GibberXmppConnection *connection, GibberXmppStanza *stanza, + gpointer user_data) +{ + if (sasl == NULL) + { + GError *err = NULL; + sasl = gibber_sasl_auth_new (); + + g_signal_connect (sasl, "username-requested", + G_CALLBACK (return_str), (gpointer)username); + g_signal_connect (sasl, "password-requested", + G_CALLBACK (return_str), (gpointer)password); + g_signal_connect (sasl, "authentication-succeeded", + G_CALLBACK (auth_success), NULL); + g_signal_connect (sasl, "authentication-failed", + G_CALLBACK (auth_failed), NULL); + + if (!gibber_sasl_auth_authenticate (sasl, servername, connection, stanza, + current_test->allow_plain, &err)) + { + got_error (err->domain, err->code, err->message); + g_error_free (err); + } + } +} + +static void +run_rest (test_t *test) +{ + TestSaslAuthServer *server; + + servertransport = GIBBER_TRANSPORT(test_transport_new (send_hook, NULL)); + + server = test_sasl_auth_server_new (servertransport, test->mech, username, + password, test->problem); + + authenticated = FALSE; + run_done = FALSE; + current_test = test; + + clienttransport = GIBBER_TRANSPORT (test_transport_new (send_hook, NULL)); + conn = gibber_xmpp_connection_new (clienttransport); + + g_signal_connect (conn, "parse-error", G_CALLBACK (parse_error), NULL); + g_signal_connect (conn, "stream-opened", G_CALLBACK (stream_opened), NULL); + g_signal_connect (conn, "stream-closed", G_CALLBACK (stream_closed), NULL); + g_signal_connect (conn, "received-stanza", + G_CALLBACK (received_stanza), NULL); + gibber_xmpp_connection_open (conn, servername, NULL, "1.0"); + + if (!run_done) + { + g_main_loop_run (mainloop); + } + + if (sasl != NULL) + { + g_object_unref (sasl); + sasl = NULL; + } + + g_object_unref (servertransport); + g_object_unref (clienttransport); + g_object_unref (conn); + + fail_if (test->domain == 0 && error != NULL); + fail_if (test->domain != 0 && error == NULL); + + if (error != NULL) + { + fail_if (test->domain != error->domain); + fail_if (test->code != error->code); + } + + if (error != NULL) + g_error_free (error); + + error = NULL; +} + +#define SUCCESS(desc, mech, allow_plain) \ + { desc, mech, allow_plain, 0, 0, SERVER_PROBLEM_NO_PROBLEM } + +#define NUMBER_OF_TEST 6 + +START_TEST (test_auth) +{ + test_t tests[NUMBER_OF_TEST] = { + SUCCESS("Normal authentication", NULL, TRUE), + SUCCESS("Disallow PLAIN", "PLAIN", TRUE), + SUCCESS("Plain method authentication", "PLAIN", TRUE), + SUCCESS("Normal DIGEST-MD5 authentication", "DIGEST-MD5", TRUE), + + { "No supported mechanisms", "NONSENSE", TRUE, + GIBBER_SASL_AUTH_ERROR, GIBBER_SASL_AUTH_ERROR_NO_SUPPORTED_MECHANISMS, + SERVER_PROBLEM_NO_PROBLEM }, + { "No sasl support in server", NULL, TRUE, + GIBBER_SASL_AUTH_ERROR, GIBBER_SASL_AUTH_ERROR_SASL_NOT_SUPPORTED, + SERVER_PROBLEM_NO_SASL }, + }; + + g_type_init (); + + mainloop = g_main_loop_new (NULL, FALSE); + + run_rest (&(tests[_i])); +} END_TEST + +TCase * +make_gibber_sasl_auth_tcase (void) +{ + TCase *tc = tcase_create ("SASL Auth"); + tcase_add_loop_test (tc, test_auth, 0, NUMBER_OF_TEST); + return tc; +} diff --git a/lib/gibber/tests/check-gibber-xmpp-connection-listener.c b/lib/gibber/tests/check-gibber-xmpp-connection-listener.c new file mode 100644 index 00000000..8dd19314 --- /dev/null +++ b/lib/gibber/tests/check-gibber-xmpp-connection-listener.c @@ -0,0 +1,120 @@ +/* + * check-gibber-xmpp-connection-listener.c - Test for + * GibberXmppConnectionListener + * Copyright (C) 2007 Collabora Ltd. + * @author Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <gibber/gibber-linklocal-transport.h> +#include <gibber/gibber-listener.h> +#include <gibber/gibber-xmpp-connection.h> +#include <gibber/gibber-xmpp-connection-listener.h> + +#include <check.h> +#include "check-gibber.h" + +gboolean got_connection; + +static void +new_connection_cb (GibberXmppConnectionListener *listener, + GibberXmppConnection *connection, + struct sockaddr *addr, + guint size, + gpointer user_data) +{ + got_connection = TRUE; +} + +static gboolean +connect_to_port (int port) +{ + GibberLLTransport *transport; + struct sockaddr_in addr; + gboolean result; + + transport = gibber_ll_transport_new (); + + memset (&addr, 0, sizeof (addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons (port); + addr.sin_addr.s_addr = inet_addr ("127.0.0.1"); + + result = gibber_ll_transport_open_sockaddr (transport, + (struct sockaddr_storage *) &addr, NULL); + + g_object_unref (transport); + return result; +} + +START_TEST (test_listen) +{ + GibberXmppConnectionListener *listener; + int port; + gboolean result; + + got_connection = FALSE; + + listener = gibber_xmpp_connection_listener_new (); + fail_if (listener == NULL); + + g_signal_connect (listener, "new-connection", G_CALLBACK (new_connection_cb), + NULL); + + for (port = 5298; port < 5400; port++) + { + GError *error = NULL; + if (gibber_xmpp_connection_listener_listen (listener, port, &error)) + break; + + fail_if (!g_error_matches (error, GIBBER_LISTENER_ERROR, + GIBBER_LISTENER_ERROR_ADDRESS_IN_USE)); + g_error_free (error); + error = NULL; + } + fail_if (port >= 5400); + + result = connect_to_port (port); + fail_if (result == FALSE); + + while (g_main_context_iteration (NULL, FALSE)) + ; + fail_if (got_connection == FALSE); + + g_object_unref (listener); + + /* listener is destroyed, connection should be refused now */ + got_connection = FALSE; + result = connect_to_port (port); + fail_if (result == TRUE); +} END_TEST + +TCase * +make_gibber_xmpp_connection_listener_tcase (void) +{ + TCase *tc = tcase_create ("GibberXmppConnectionListener"); + tcase_add_test (tc, test_listen); + return tc; +} diff --git a/lib/gibber/tests/check-gibber-xmpp-connection.c b/lib/gibber/tests/check-gibber-xmpp-connection.c new file mode 100644 index 00000000..de9dd1da --- /dev/null +++ b/lib/gibber/tests/check-gibber-xmpp-connection.c @@ -0,0 +1,126 @@ +#include <stdio.h> +#include <unistd.h> +#include <glib.h> + +#include <gibber/gibber-xmpp-connection.h> +#include <gibber/gibber-transport.h> +#include "test-transport.h" +#include "check-gibber.h" + +#include <check.h> + +struct _FileChunker { + gchar *contents; + gsize length; + gsize size; + gsize offset; +}; +typedef struct _FileChunker FileChunker; + +static void +file_chunker_destroy (FileChunker *fc) { + g_free (fc->contents); + g_free (fc); +} + + +static FileChunker * +file_chunker_new (const gchar *filename, gsize chunk_size) { + FileChunker *fc; + fc = g_new0 (FileChunker, 1); + + fc->size = chunk_size; + if (!g_file_get_contents (filename, &fc->contents, &fc->length, NULL)) { + file_chunker_destroy (fc); + return NULL; + } + return fc; +} + +static gboolean +file_chunker_get_chunk (FileChunker *fc, + gchar **chunk, + gsize *chunk_size) { + if (fc->offset < fc->length) { + *chunk_size = MIN (fc->length - fc->offset, fc->size); + *chunk = fc->contents + fc->offset; + fc->offset += *chunk_size; + return TRUE; + } + return FALSE; +} + + +START_TEST (test_instantiation) +{ + GibberXmppConnection *connection; + TestTransport *transport; + + transport = test_transport_new (NULL, NULL); + connection = gibber_xmpp_connection_new (GIBBER_TRANSPORT(transport)); + + fail_if (connection == NULL); + + connection = gibber_xmpp_connection_new (NULL); + + fail_if (connection == NULL); +} +END_TEST + +static void +parse_error_cb (GibberXmppConnection *connection, gpointer user_data) +{ + gboolean *parse_error_found = user_data; + *parse_error_found = TRUE; +} + +START_TEST (test_simple_message) +{ + GibberXmppConnection *connection; + TestTransport *transport; + gchar *chunk; + gsize chunk_length; + gboolean parse_error_found = FALSE; + const gchar *srcdir; + gchar *file; + FileChunker *fc; + + srcdir = g_getenv ("srcdir"); + if (srcdir == NULL) + { + file = g_strdup ("inputs/simple-message.input"); + } + else + { + file = g_strdup_printf ("%s/inputs/simple-message.input", srcdir); + } + + fc = file_chunker_new (file, 10); + fail_if (fc == NULL); + + transport = test_transport_new (NULL, NULL); + connection = gibber_xmpp_connection_new (GIBBER_TRANSPORT(transport)); + + g_signal_connect (connection, "parse-error", + G_CALLBACK(parse_error_cb), &parse_error_found); + + while (!parse_error_found && + file_chunker_get_chunk (fc, &chunk, &chunk_length)) + { + test_transport_write (transport, (guint8 *) chunk, chunk_length); + } + + fail_if (parse_error_found); + + g_free (file); + file_chunker_destroy (fc); +} END_TEST + +TCase * +make_gibber_xmpp_connection_tcase (void) +{ + TCase *tc = tcase_create ("XMPP Connection"); + tcase_add_test (tc, test_instantiation); + tcase_add_test (tc, test_simple_message); + return tc; +} diff --git a/lib/gibber/tests/check-gibber-xmpp-error.c b/lib/gibber/tests/check-gibber-xmpp-error.c new file mode 100644 index 00000000..3acc61c7 --- /dev/null +++ b/lib/gibber/tests/check-gibber-xmpp-error.c @@ -0,0 +1,139 @@ +/* + * check-gibber-xmpp-error.c - Test for gibber-xmpp-error functions + * Copyright (C) 2007 Collabora Ltd. + * @author Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <gibber/gibber-xmpp-error.h> + +#define DEBUG_FLAG DEBUG_XMPP +#include <gibber/gibber-debug.h> + +#include <check.h> +#include "check-gibber.h" + +static void +test_xmpp_error_to_node_with_bad_request (void) +{ + GibberXmppStanza *stanza; + GibberXmppNode *node; + const gchar *code; + const gchar *type; + + stanza = gibber_xmpp_stanza_build ( + GIBBER_STANZA_TYPE_IQ, GIBBER_STANZA_SUB_TYPE_ERROR, + "from", "to", + GIBBER_STANZA_END); + node = gibber_xmpp_error_to_node (XMPP_ERROR_BAD_REQUEST, stanza->node, + NULL); + + fail_if (node == NULL); + fail_if (strcmp (node->name, "error") != 0); + + code = gibber_xmpp_node_get_attribute (node, "code"); + fail_if (code == NULL || strcmp (code, "400") != 0); + + type = gibber_xmpp_node_get_attribute (node, "type"); + fail_if (type == NULL || strcmp (type, "modify") != 0); + + fail_if (gibber_xmpp_node_get_child_ns (node, "bad-request", + "urn:ietf:params:xml:ns:xmpp-stanzas") == NULL); + + g_object_unref (stanza); +} + +static void +test_xmpp_error_to_node_with_si_bad_profile (void) +{ + GibberXmppStanza *stanza; + GibberXmppNode *node; + const gchar *code; + const gchar *type; + + stanza = gibber_xmpp_stanza_build ( + GIBBER_STANZA_TYPE_IQ, GIBBER_STANZA_SUB_TYPE_ERROR, + "from", "to", + GIBBER_STANZA_END); + node = gibber_xmpp_error_to_node (XMPP_ERROR_SI_BAD_PROFILE, stanza->node, + NULL); + + fail_if (node == NULL); + fail_if (strcmp (node->name, "error") != 0); + + code = gibber_xmpp_node_get_attribute (node, "code"); + fail_if (code == NULL || strcmp (code, "400") != 0); + + type = gibber_xmpp_node_get_attribute (node, "type"); + fail_if (type == NULL || strcmp (type, "modify") != 0); + + fail_if (gibber_xmpp_node_get_child_ns (node, "bad-request", + "urn:ietf:params:xml:ns:xmpp-stanzas") == NULL); + + fail_if (gibber_xmpp_node_get_child_ns (node, "bad-profile", + "http://jabber.org/protocol/si") == NULL); + + g_object_unref (stanza); +} + +START_TEST (test_xmpp_error_to_node) +{ + test_xmpp_error_to_node_with_bad_request (); + test_xmpp_error_to_node_with_si_bad_profile (); +} END_TEST + +START_TEST (test_message_get_xmpp_error) +{ + GibberXmppError xmpp_error; + + for (xmpp_error = 1; xmpp_error < NUM_XMPP_ERRORS; xmpp_error++) + { + GibberXmppStanza *stanza; + GError *error = NULL; + + stanza = gibber_xmpp_stanza_build ( + GIBBER_STANZA_TYPE_IQ, GIBBER_STANZA_SUB_TYPE_ERROR, + "from", "to", + GIBBER_STANZA_END); + gibber_xmpp_error_to_node (xmpp_error, stanza->node, NULL); + + error = gibber_message_get_xmpp_error (stanza); + fail_if (error == NULL); + + fail_if (error->domain != GIBBER_XMPP_ERROR); + fail_if (error->code != (gint) xmpp_error); + fail_if (strcmp (error->message, gibber_xmpp_error_description ( + xmpp_error)) != 0); + + g_object_unref (stanza); + g_error_free (error); + } + +} END_TEST + +TCase * +make_gibber_xmpp_error_tcase (void) +{ + TCase *tc = tcase_create ("XMPP Error"); + tcase_add_test (tc, test_xmpp_error_to_node); + tcase_add_test (tc, test_message_get_xmpp_error); + return tc; +} diff --git a/lib/gibber/tests/check-gibber-xmpp-node.c b/lib/gibber/tests/check-gibber-xmpp-node.c new file mode 100644 index 00000000..3f5ea32c --- /dev/null +++ b/lib/gibber/tests/check-gibber-xmpp-node.c @@ -0,0 +1,167 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <gibber/gibber-xmpp-node.h> + +#include <check.h> +#include "check-helpers.h" +#include "check-gibber.h" + +START_TEST (test_instantiation) +{ + GibberXmppNode *node; + node = gibber_xmpp_node_new ("test"); + fail_unless (node != NULL); + + gibber_xmpp_node_free (node); + + node = gibber_xmpp_node_new (NULL); + fail_unless (node != NULL); + + gibber_xmpp_node_free (node); +} +END_TEST + +START_TEST (test_language) +{ + GibberXmppNode *node; + const gchar *lang; + + /* Unit test are not examples of how to use an API! Don't rely on the + * following in your applications! (or better yet, don't give invalid input) + * */ + fail_unless_critical (lang = gibber_xmpp_node_get_language (NULL)); + fail_unless (lang == NULL); + + node = gibber_xmpp_node_new ("test"); + lang = gibber_xmpp_node_get_language (node); + fail_unless (lang == NULL); + + gibber_xmpp_node_set_language (node, "en"); + lang = gibber_xmpp_node_get_language (node); + fail_unless (strcmp (lang, "en") == 0); + + gibber_xmpp_node_set_language (node, NULL); + lang = gibber_xmpp_node_get_language (node); + fail_unless (lang == NULL); + + gibber_xmpp_node_set_language_n (node, "en-US", 2); + lang = gibber_xmpp_node_get_language (node); + fail_unless (strcmp (lang, "en") == 0); + + gibber_xmpp_node_set_language_n (node, NULL, 2); + lang = gibber_xmpp_node_get_language (node); + fail_unless (lang == NULL); + + gibber_xmpp_node_free (node); +} +END_TEST + +START_TEST (test_namespace) +{ + GibberXmppNode *node; + const gchar *ns; + + node = gibber_xmpp_node_new ("test"); + + ns = gibber_xmpp_node_get_ns (node); + fail_unless (ns == NULL); + + gibber_xmpp_node_set_ns (node, "foo"); + ns = gibber_xmpp_node_get_ns (node); + fail_unless (strcmp (ns, "foo") == 0); + + gibber_xmpp_node_set_ns (node, NULL); + ns = gibber_xmpp_node_get_ns (node); + fail_unless (ns == NULL); + + gibber_xmpp_node_free (node); +} +END_TEST + + +START_TEST (test_attribute) +{ + GibberXmppNode *node; + const gchar *attribute; + + node = gibber_xmpp_node_new ("test"); + + attribute = gibber_xmpp_node_get_attribute (node, "foo"); + fail_unless (attribute == NULL); + + attribute = gibber_xmpp_node_get_attribute (node, NULL); + fail_unless (attribute == NULL); + + attribute = gibber_xmpp_node_get_attribute_ns (node, "foo", "bar"); + fail_unless (attribute == NULL); + + gibber_xmpp_node_set_attribute (node, "foo", "baz"); + + attribute = gibber_xmpp_node_get_attribute (node, "foo"); + fail_unless (strcmp ( attribute, "baz") == 0); + + attribute = gibber_xmpp_node_get_attribute_ns (node, "foo", "bar"); + fail_unless (attribute == NULL); + + gibber_xmpp_node_set_attribute_ns (node, "foobar", "barbaz", "bar"); + + attribute = gibber_xmpp_node_get_attribute (node, "foobar"); + fail_unless (strcmp (attribute, "barbaz") == 0); + + attribute = gibber_xmpp_node_get_attribute_ns (node, "foobar", "bar"); + fail_unless (strcmp (attribute, "barbaz") == 0); + + attribute = gibber_xmpp_node_get_attribute_ns (node, "barfoo", "bar"); + fail_unless (attribute == NULL); + + gibber_xmpp_node_free (node); +} +END_TEST + +START_TEST (test_child) +{ + GibberXmppNode *node, *child; + + node = gibber_xmpp_node_new ("test"); + + child = gibber_xmpp_node_get_child (node, "foo"); + fail_unless (child == NULL); + + gibber_xmpp_node_add_child (node, "foo"); + child = gibber_xmpp_node_get_child (node, "foo"); + fail_if (child == NULL); + fail_unless (strcmp (child->name, "foo") == 0); + + child = gibber_xmpp_node_get_child_ns (node, "foo", "bar"); + fail_unless (child == NULL); + + gibber_xmpp_node_add_child_ns (node, "foobar", "bar"); + child = gibber_xmpp_node_get_child_ns (node, "foobar", "foo"); + fail_unless (child == NULL); + child = gibber_xmpp_node_get_child_ns (node, "foobar", "bar"); + fail_if (child == NULL); + fail_unless (strcmp (child->name, "foobar") == 0); + + gibber_xmpp_node_add_child_with_content (node, "foo2", "blah"); + child = gibber_xmpp_node_get_child (node, "foo2"); + fail_if (child->content == NULL); + fail_unless (strcmp (child->content, "blah") == 0); + + gibber_xmpp_node_free (node); +} +END_TEST + + +TCase * +make_gibber_xmpp_node_tcase (void) +{ + TCase *tc = tcase_create ("XMPP Node"); + tcase_add_test (tc, test_instantiation); + tcase_add_test (tc, test_language); + tcase_add_test (tc, test_namespace); + tcase_add_test (tc, test_attribute); + tcase_add_test (tc, test_child); + return tc; +} diff --git a/lib/gibber/tests/check-gibber-xmpp-reader.c b/lib/gibber/tests/check-gibber-xmpp-reader.c new file mode 100644 index 00000000..d6bb8b04 --- /dev/null +++ b/lib/gibber/tests/check-gibber-xmpp-reader.c @@ -0,0 +1,127 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <gibber/gibber-xmpp-reader.h> +#include <gibber/gibber-xmpp-stanza.h> + +#include <check.h> + +#include "check-gibber.h" + +typedef struct _ReceivedStanzaEvent ReceivedStanzaEvent; + +struct _ReceivedStanzaEvent { + GibberXmppReader *reader; + GibberXmppStanza *stanza; +}; + +static void received_stanza_cb (GibberXmppReader *reader, + GibberXmppStanza *stanza, gpointer user_data) +{ + GQueue *events_queue = (GQueue *) user_data; + ReceivedStanzaEvent *event; + + fail_if (reader == NULL); + fail_if (stanza == NULL); + fail_if (events_queue == NULL); + + g_object_ref (stanza); + + event = g_new (ReceivedStanzaEvent, 1); + event->reader = reader; + event->stanza = stanza; + + g_queue_push_tail (events_queue, event); +} + + +START_TEST (test_instantiation) +{ + GibberXmppReader *reader; + reader = gibber_xmpp_reader_new_no_stream (); + fail_if (reader == NULL); + g_object_unref (reader); +} +END_TEST + +START_TEST (test_simple_message) +{ + GibberXmppReader *reader; + GibberXmppNode *node; + gchar *data; + gsize length; + gboolean valid; + GQueue *received_stanzas; + ReceivedStanzaEvent *event; + const gchar *srcdir; + gchar *file; + + received_stanzas = g_queue_new (); + + reader = gibber_xmpp_reader_new (); + g_signal_connect (reader, "received-stanza", + G_CALLBACK (received_stanza_cb), received_stanzas); + + srcdir = g_getenv ("srcdir"); + if (srcdir == NULL) + { + file = g_strdup ("inputs/simple-message.input"); + } + else + { + file = g_strdup_printf ("%s/inputs/simple-message.input", srcdir); + } + + fail_unless (g_file_get_contents (file, &data, &length, NULL)); + g_free (file); + + valid = gibber_xmpp_reader_push (reader, (guint8 *) data, length, NULL); + fail_unless (valid); + + fail_unless (g_queue_get_length (received_stanzas) == 2); + + event = g_queue_pop_head (received_stanzas); + + fail_unless (event->reader == reader); + + node = event->stanza->node; + fail_if (node == NULL); + fail_unless (strcmp (node->name, "message") == 0); + fail_unless (strcmp (gibber_xmpp_node_get_language (node), "en") == 0); + fail_unless (strcmp (gibber_xmpp_node_get_attribute (node, "to"), + "juliet@example.com") == 0); + fail_unless (strcmp (gibber_xmpp_node_get_attribute (node, "id"), + "0") == 0); + + g_object_unref (event->stanza); + g_free (event); + + event = g_queue_pop_head (received_stanzas); + + fail_unless (event->reader == reader); + + node = event->stanza->node; + fail_unless (strcmp (node->name, "message") == 0); + fail_unless (strcmp (gibber_xmpp_node_get_language (node), "en") == 0); + fail_unless (strcmp (gibber_xmpp_node_get_attribute (node, "to"), + "juliet@example.com") == 0); + fail_unless (strcmp (gibber_xmpp_node_get_attribute (node, "id"), + "1") == 0); + + g_free (data); + g_queue_free (received_stanzas); + g_object_unref (event->stanza); + g_free (event); + g_object_unref (reader); +} +END_TEST + +TCase * +make_gibber_xmpp_reader_tcase (void) +{ + TCase *tc = tcase_create ("XMPP Reader"); + tcase_add_test (tc, test_instantiation); + tcase_add_test (tc, test_simple_message); + return tc; +} diff --git a/lib/gibber/tests/check-gibber-xmpp-stanza.c b/lib/gibber/tests/check-gibber-xmpp-stanza.c new file mode 100644 index 00000000..ab0e62d4 --- /dev/null +++ b/lib/gibber/tests/check-gibber-xmpp-stanza.c @@ -0,0 +1,165 @@ +/* + * check-gibber-xmpp-stanza.c - Test for gibber-xmpp-stanza functions + * Copyright (C) 2007 Collabora Ltd. + * @author Guillaume Desmottes <guillaume.desmottes@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <gibber/gibber-xmpp-stanza.h> + +#define DEBUG_FLAG DEBUG_XMPP +#include <gibber/gibber-debug.h> + +#include <check.h> +#include "check-gibber.h" + +START_TEST (test_build_with_html_message) +{ + GibberXmppStanza *stanza; + const gchar *body = "Telepathy rocks!", + *xhtml_ns = "http://www.w3.org/1999/xhtml"; + GibberXmppNode *node; + const gchar *value; + + g_type_init (); +#ifdef ENABLE_DEBUG + gibber_debug_set_flags_from_env (); +#endif + + stanza = gibber_xmpp_stanza_build ( + GIBBER_STANZA_TYPE_MESSAGE, GIBBER_STANZA_SUB_TYPE_NONE, + "alice@collabora.co.uk", "bob@collabora.co.uk", + GIBBER_NODE, "html", + GIBBER_NODE_XMLNS, xhtml_ns, + GIBBER_NODE, "body", + GIBBER_NODE_ATTRIBUTE, "textcolor", "red", + GIBBER_NODE_TEXT, body, + GIBBER_NODE_END, + GIBBER_NODE_END, + GIBBER_STANZA_END); + + DEBUG_STANZA (stanza, "check"); + + fail_if (stanza == NULL); + /* <message> */ + node = stanza->node; + fail_if (node == NULL); + fail_unless (strcmp (node->name, "message") == 0); + value = gibber_xmpp_node_get_attribute (node, "type"); + fail_unless (value == NULL); + value = gibber_xmpp_node_get_attribute (node, "from"); + fail_unless (strcmp (value, "alice@collabora.co.uk") == 0); + value = gibber_xmpp_node_get_attribute (node, "to"); + fail_unless (strcmp (value, "bob@collabora.co.uk") == 0); + + /* <html> */ + node = gibber_xmpp_node_get_child_ns (node, "html", xhtml_ns); + fail_if (node == NULL); + + /* <body> */ + node = gibber_xmpp_node_get_child (node, "body"); + fail_if (node == NULL); + value = gibber_xmpp_node_get_attribute (node, "textcolor"); + fail_unless (strcmp (value, "red") == 0); + fail_unless (strcmp (node->content, body) == 0); + + g_object_unref (stanza); +} END_TEST + +START_TEST (test_get_type_info_with_simple_message) +{ + GibberXmppStanza *stanza; + GibberStanzaType type; + GibberStanzaSubType sub_type; + + stanza = gibber_xmpp_stanza_build ( + GIBBER_STANZA_TYPE_MESSAGE, GIBBER_STANZA_SUB_TYPE_NONE, + "alice@collabora.co.uk", "bob@collabora.co.uk", + GIBBER_STANZA_END); + fail_if (stanza == NULL); + + gibber_xmpp_stanza_get_type_info (stanza, &type, &sub_type); + fail_if (type != GIBBER_STANZA_TYPE_MESSAGE); + fail_if (sub_type != GIBBER_STANZA_SUB_TYPE_NONE); + + g_object_unref (stanza); +} END_TEST + +START_TEST (test_get_type_info_with_iq_set) +{ + GibberXmppStanza *stanza; + GibberStanzaType type; + GibberStanzaSubType sub_type; + + stanza = gibber_xmpp_stanza_build ( + GIBBER_STANZA_TYPE_IQ, GIBBER_STANZA_SUB_TYPE_SET, + "alice@collabora.co.uk", "bob@collabora.co.uk", + GIBBER_STANZA_END); + fail_if (stanza == NULL); + + gibber_xmpp_stanza_get_type_info (stanza, &type, &sub_type); + fail_if (type != GIBBER_STANZA_TYPE_IQ); + fail_if (sub_type != GIBBER_STANZA_SUB_TYPE_SET); + + g_object_unref (stanza); +} END_TEST + +START_TEST (test_get_type_info_with_unknown_type) +{ + GibberXmppStanza *stanza; + GibberStanzaType type; + + stanza = gibber_xmpp_stanza_new ("goat"); + fail_if (stanza == NULL); + + gibber_xmpp_stanza_get_type_info (stanza, &type, NULL); + fail_if (type != GIBBER_STANZA_TYPE_UNKNOWN); + + g_object_unref (stanza); +} END_TEST + +START_TEST (test_get_type_info_with_unknown_sub_type) +{ + GibberXmppStanza *stanza; + GibberStanzaSubType sub_type; + + stanza = gibber_xmpp_stanza_new ("iq"); + fail_if (stanza == NULL); + gibber_xmpp_node_set_attribute (stanza->node, "type", "goat"); + + gibber_xmpp_stanza_get_type_info (stanza, NULL, &sub_type); + fail_if (sub_type != GIBBER_STANZA_SUB_TYPE_UNKNOWN); + + g_object_unref (stanza); +} END_TEST + + +TCase * +make_gibber_xmpp_stanza_tcase (void) +{ + TCase *tc = tcase_create ("XMPP Stanza"); + tcase_add_test (tc, test_build_with_html_message); + tcase_add_test (tc, test_get_type_info_with_simple_message); + tcase_add_test (tc, test_get_type_info_with_iq_set); + tcase_add_test (tc, test_get_type_info_with_unknown_type); + tcase_add_test (tc, test_get_type_info_with_unknown_sub_type); + return tc; +} diff --git a/lib/gibber/tests/check-gibber.h b/lib/gibber/tests/check-gibber.h new file mode 100644 index 00000000..edd747ff --- /dev/null +++ b/lib/gibber/tests/check-gibber.h @@ -0,0 +1,20 @@ +#ifndef __CHECK_GIBBER_H__ +#define __CHECK_GIBBER_H__ + +#include <check.h> + +TCase *make_gibber_xmpp_node_tcase (void); +TCase *make_gibber_xmpp_reader_tcase (void); +TCase *make_gibber_xmpp_connection_tcase (void); +TCase *make_gibber_sasl_auth_tcase (void); +TCase *make_gibber_resolver_tcase (void); +TCase *make_gibber_r_multicast_packet_tcase (void); +TCase *make_gibber_r_multicast_causal_transport_tcase (void); +TCase *make_gibber_r_multicast_sender_tcase (void); +TCase *make_gibber_xmpp_stanza_tcase (void); +TCase *make_gibber_iq_helper_tcase (void); +TCase *make_gibber_listener_tcase (void); +TCase *make_gibber_xmpp_connection_listener_tcase (void); +TCase *make_gibber_xmpp_error_tcase (void); + +#endif /* #ifndef __CHECK_GIBBER_H__ */ diff --git a/lib/gibber/tests/check-helpers.c b/lib/gibber/tests/check-helpers.c new file mode 100644 index 00000000..86ef1154 --- /dev/null +++ b/lib/gibber/tests/check-helpers.c @@ -0,0 +1,63 @@ +/* + * check-helpers.c - Source for some check helpers + * Copyright (C) 2007 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "check-helpers.h" + +static gboolean expecting_critical = FALSE; +static gboolean received_critical = FALSE; + +static void +check_helper_log_critical_func (const gchar *log_damain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data) +{ + + if (!expecting_critical) + { + fail ("Unexpected critical message: %s\n", message); + } + + g_assert (log_level & G_LOG_LEVEL_CRITICAL); + + received_critical = TRUE; +} + +gboolean +got_critical (void) +{ + return received_critical; +} + +void +expect_critical (gboolean expected) +{ + expecting_critical = expected; + received_critical = FALSE; +} + +void +check_helpers_init (void) +{ + g_log_set_handler (NULL, G_LOG_LEVEL_CRITICAL, + check_helper_log_critical_func, NULL); +} diff --git a/lib/gibber/tests/check-helpers.h b/lib/gibber/tests/check-helpers.h new file mode 100644 index 00000000..b71b3b65 --- /dev/null +++ b/lib/gibber/tests/check-helpers.h @@ -0,0 +1,43 @@ +/* + * check-helpers.c - Source for some check helpers + * Copyright (C) 2007 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef __CHECK_HELPERS_H__ +#define __CHECK_HELPERS_H__ + +#include <glib.h> +#include <check.h> + +void +check_helpers_init (void); + +void +expect_critical (gboolean expected); + +gboolean +got_critical (void); + +#define fail_unless_critical(expr, ...) \ +G_STMT_START { \ + expect_critical (TRUE); \ + expr; \ + _fail_unless (got_critical (), __FILE__, __LINE__, \ + "Expected g_critical, got none", ## __VA_ARGS__, NULL); \ + expect_critical (FALSE); \ +} G_STMT_END; + +#endif /* #ifndef __CHECK_HELPERS_H__ */ diff --git a/lib/gibber/tests/check-main.c b/lib/gibber/tests/check-main.c new file mode 100644 index 00000000..cf01cfe4 --- /dev/null +++ b/lib/gibber/tests/check-main.c @@ -0,0 +1,54 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <glib-object.h> + +#include <check.h> + +#include "check-gibber.h" +#include "check-helpers.h" + +#include "config.h" + +static Suite * +make_gibber_suite (void) +{ + Suite *s = suite_create ("Gibber"); + + suite_add_tcase (s, make_gibber_xmpp_node_tcase ()); + suite_add_tcase (s, make_gibber_xmpp_reader_tcase ()); + suite_add_tcase (s, make_gibber_xmpp_connection_tcase ()); +#ifdef HAVE_LIBSASL2 + suite_add_tcase (s, make_gibber_sasl_auth_tcase ()); +#endif + suite_add_tcase (s, make_gibber_resolver_tcase ()); + suite_add_tcase (s, make_gibber_r_multicast_packet_tcase ()); + suite_add_tcase (s, make_gibber_r_multicast_sender_tcase ()); + suite_add_tcase (s, make_gibber_r_multicast_causal_transport_tcase ()); + suite_add_tcase (s, make_gibber_xmpp_stanza_tcase ()); + suite_add_tcase (s, make_gibber_iq_helper_tcase ()); + suite_add_tcase (s, make_gibber_listener_tcase ()); + suite_add_tcase (s, make_gibber_xmpp_connection_listener_tcase ()); + suite_add_tcase (s, make_gibber_xmpp_error_tcase ()); + + return s; +} + +int +main (void) +{ + int number_failed = 0; + Suite *s; + SRunner *sr; + + check_helpers_init (); + g_type_init (); + + s = make_gibber_suite (); + sr = srunner_create (s); + srunner_run_all (sr, CK_NORMAL); + number_failed += srunner_ntests_failed (sr); + srunner_free (sr); + + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/lib/gibber/tests/inputs/Makefile.am b/lib/gibber/tests/inputs/Makefile.am new file mode 100644 index 00000000..0b8b19f3 --- /dev/null +++ b/lib/gibber/tests/inputs/Makefile.am @@ -0,0 +1,5 @@ +EXTRA_DIST = \ + groupchat-invite.input \ + simple-message-attrnamespace.input \ + simple-message.input \ + strange-streamopening.input diff --git a/lib/gibber/tests/inputs/groupchat-invite.input b/lib/gibber/tests/inputs/groupchat-invite.input new file mode 100644 index 00000000..3c7954f4 --- /dev/null +++ b/lib/gibber/tests/inputs/groupchat-invite.input @@ -0,0 +1,32 @@ +<?xml version='1.0' encoding='UTF-8'?> +<stream:stream xmlns='jabber:client' + xmlns:stream='http://etherx.jabber.org/streams'> + +<message + from='crone1@shakespeare.lit/desktop' + to='darkcave@macbeth.shakespeare.lit' id="0"> + <x xmlns='http://jabber.org/protocol/muc#user'> + <invite to='hecate@shakespeare.lit'> + <reason> + Hey Hecate, this is the place for all good witches! + </reason> + </invite> + </x> +</message> + +<message + from='darkcave@macbeth.shakespeare.lit' + to='hecate@shakespeare.lit' id="1"> + <body>You have been invited to darkcave@macbeth by crone1@shakespeare.lit.</body> + <x xmlns='http://jabber.org/protocol/muc#user'> + <invite from='crone1@shakespeare.lit'> + <reason> + Hey Hecate, this is the place for all good witches! + </reason> + </invite> + <password>cauldronburn</password> + </x> +</message> + + +</stream:stream> diff --git a/lib/gibber/tests/inputs/simple-message-attrnamespace.input b/lib/gibber/tests/inputs/simple-message-attrnamespace.input new file mode 100644 index 00000000..b85d92f6 --- /dev/null +++ b/lib/gibber/tests/inputs/simple-message-attrnamespace.input @@ -0,0 +1,17 @@ +<?xml version='1.0' encoding='UTF-8'?> +<stream:stream xmlns='jabber:client' + xmlns:stream='http://etherx.jabber.org/streams'> + + <message to='juliet@example.com' from='romeo@example.net' xml:lang='en' + id="0"> + <body>Art thou not Romeo, and a Montague?</body> + </message> + + <message from='romeo@example.net' + to='juliet@example.com' + stream:blaat='blaat' + xml:lang='en' id="1"> + <body>Neither, fair saint, if either thee dislike.</body> + </message> + +</stream:stream> diff --git a/lib/gibber/tests/inputs/simple-message.input b/lib/gibber/tests/inputs/simple-message.input new file mode 100644 index 00000000..a3989ae5 --- /dev/null +++ b/lib/gibber/tests/inputs/simple-message.input @@ -0,0 +1,16 @@ +<?xml version='1.0' encoding='UTF-8'?> +<stream:stream xmlns='jabber:client' + xmlns:stream='http://etherx.jabber.org/streams'> + + <message to='juliet@example.com' from='romeo@example.net' xml:lang='en' + id="0"> + <body>Art thou not Romeo, and a Montague?</body> + </message> + + <message from='romeo@example.net' + to='juliet@example.com' + xml:lang='en' id="1"> + <body>Neither, fair saint, if either thee dislike.</body> + </message> + +</stream:stream> diff --git a/lib/gibber/tests/inputs/strange-streamopening.input b/lib/gibber/tests/inputs/strange-streamopening.input new file mode 100644 index 00000000..4685541a --- /dev/null +++ b/lib/gibber/tests/inputs/strange-streamopening.input @@ -0,0 +1,9 @@ +<?xml version='1.0' encoding='utf-8'?> +<stream:stream xmlns='jabber:client' + xmlns:stream='http://etherx.jabber.org/streams' + from='rome"&@example.net' + to='ex"&ample.net'> + + <aap bla="&" id="0"/> + +</stream:stream> diff --git a/lib/gibber/tests/inputs/tls-stream-start.input b/lib/gibber/tests/inputs/tls-stream-start.input new file mode 100644 index 00000000..d30bcf88 --- /dev/null +++ b/lib/gibber/tests/inputs/tls-stream-start.input @@ -0,0 +1,18 @@ +<stream:stream + xmlns='jabber:client' + xmlns:stream='http://etherx.jabber.org/streams' + to='example.com' + version='1.0'> + + <stream:features id="0"> + <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'> + <required/> + </starttls> + <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> + <mechanism>DIGEST-MD5</mechanism> + <mechanism>PLAIN</mechanism> + </mechanisms> + </stream:features> + + <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' id="1"/> +</stream:stream> diff --git a/lib/gibber/tests/run-xmpp-connection-test.sh b/lib/gibber/tests/run-xmpp-connection-test.sh new file mode 100755 index 00000000..e2337abc --- /dev/null +++ b/lib/gibber/tests/run-xmpp-connection-test.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +mkdir -p outputs + +RET=0 + + +srcdir=${srdir:=$(dirname $0)} + +for x in ${srcdir}/inputs/*.input ; do + FILE=$(basename ${x%.input}) + XMLOUT="outputs/${FILE}.output" + PARSEOUT="outputs/${FILE}.parse" + ./test-xmpp-connection $x ${PARSEOUT} ${XMLOUT} + if [ $? -ne 0 ] ; then + echo "FAILED: $x - Test program had non-zero exit status" >&2 + RET=1 + continue + fi + xmldiff $x $XMLOUT + if [ $? -ne 0 ] ; then + echo "FAILED: $x - XML output doesn't match the input" >&2 + RET=1 + continue + fi + echo "SUCCESS: $x" >&2 +done + +exit ${RET} diff --git a/lib/gibber/tests/test-r-multicast-transport-io.c b/lib/gibber/tests/test-r-multicast-transport-io.c new file mode 100644 index 00000000..62a4e96d --- /dev/null +++ b/lib/gibber/tests/test-r-multicast-transport-io.c @@ -0,0 +1,226 @@ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <glib.h> + +#include <gibber/gibber-r-multicast-transport.h> +#include <gibber/gibber-debug.h> +#include "test-transport.h" + +GMainLoop *loop; + +TestTransport *t; +GibberRMulticastTransport *rm; +GibberRMulticastCausalTransport *rmc; +gulong rmc_connected_handler = 0; + +static void +received_data (GibberTransport *transport, GibberBuffer *buffer, + gpointer user_data) +{ + GibberRMulticastBuffer *rmbuffer = (GibberRMulticastBuffer *) buffer; + gchar *b64; + + b64 = g_base64_encode ((guchar *) buffer->data, buffer->length); + printf ("OUTPUT:%s:%s\n", rmbuffer->sender, b64); + fflush (stdout); + g_free (b64); +} + +static gboolean +send_hook (GibberTransport *transport, const guint8 *data, gsize length, + GError **error, gpointer user_data) +{ + gchar *b64; + + b64 = g_base64_encode ((guchar *) data, length); + printf ("SEND:%s\n", b64); + fflush (stdout); + g_free (b64); + + return TRUE; +} + +static void +fail_node (gchar *name) +{ + GibberRMulticastSender *sender; + + name = g_strstrip (name); + + sender = gibber_r_multicast_causal_transport_get_sender_by_name (rmc, name); + g_assert (sender != NULL); + + _gibber_r_multicast_TEST_sender_fail (sender); +} + +static gboolean +got_input (GIOChannel *source, GIOCondition condition, gpointer user_data) +{ + GIOStatus s; + gchar *buffer; + gsize len; + gchar *p; + gboolean packet = FALSE; + guchar *b64; + gsize size; + + s = g_io_channel_read_line (source, &buffer, &len, NULL, NULL); + g_assert (s == G_IO_STATUS_NORMAL); + + if (g_str_has_prefix (buffer, "INPUT:")) + { + packet = FALSE; + p = buffer + strlen ("INPUT:"); + } + else if (g_str_has_prefix (buffer, "RECV:")) + { + packet = TRUE; + p = buffer + strlen ("RECV:"); + } + else if (strcmp (buffer, "DISCONNECT\n") == 0) + { + gibber_transport_disconnect (GIBBER_TRANSPORT(rm)); + goto out; + } + else if (g_str_has_prefix (buffer, "FAIL:")) + { + /* this will modify our buffer */ + fail_node (buffer + strlen ("FAIL:")); + goto out; + } + else + { + g_assert_not_reached (); + } + + b64 = g_base64_decode (p, &size); + + if (packet) + { + test_transport_write (t, b64, size); + } + else + { + g_assert (gibber_transport_send (GIBBER_TRANSPORT (rm), + b64, size, NULL)); + } + + g_free (b64); +out: + g_free (buffer); + + return TRUE; +} + +static gboolean +got_error (GIOChannel *source, GIOCondition condition, gpointer user_data) +{ + g_main_loop_quit (loop); + fprintf (stderr, "error"); + fflush (stderr); + return TRUE; +} + +static void +new_senders_cb (GibberRMulticastTransport *transport, + GArray *names, gpointer user_data) +{ + guint i; + GString *str = g_string_new ("NEWNODES:"); + + for (i = 0; i < names->len; i++) + { + g_string_append_printf (str, "%s ", g_array_index (names, gchar *, i)); + } + printf ("%s\n", str->str); + g_string_free (str, TRUE); + fflush (stdout); +} + +static void +lost_senders_cb (GibberRMulticastTransport *transport, + GArray *names, gpointer user_data) +{ + guint i; + GString *str = g_string_new ("LOSTNODES:"); + + for (i = 0; i < names->len; i++) + { + g_string_append_printf (str, "%s ", g_array_index (names, gchar *, i)); + } + printf ("%s\n", str->str); + g_string_free (str, TRUE); + fflush (stdout); +} + +static void +rm_connected (GibberRMulticastTransport *transport, gpointer user_data) +{ + printf ("CONNECTED:\n"); + fflush (stdout); +} + +static void +rm_disconnected (GibberRMulticastTransport *transport, gpointer user_data) +{ + printf ("DISCONNECTED:\n"); + fflush (stdout); + g_main_loop_quit (loop); +} + +static void +rmc_connected (GibberRMulticastTransport *transport, gpointer user_data) +{ + g_assert (gibber_r_multicast_transport_connect (rm, NULL)); + g_signal_handler_disconnect (transport, rmc_connected_handler); +} + +int +main (int argc, char **argv) +{ + GIOChannel *io; + + g_assert (argc == 2); + + g_type_init (); + + printf ("Starting process %d for %s\n", getpid (), argv[1]); + + loop = g_main_loop_new (NULL, FALSE); + + t = test_transport_new (send_hook, argv[1]); + GIBBER_TRANSPORT (t)->max_packet_size = 1500; + test_transport_set_echoing (t, TRUE); + + rmc = gibber_r_multicast_causal_transport_new (GIBBER_TRANSPORT (t), + argv[1]); + g_object_unref (t); + + rm = gibber_r_multicast_transport_new (rmc); + gibber_transport_set_handler (GIBBER_TRANSPORT (rm), received_data, argv[1]); + g_object_unref (rmc); + + g_signal_connect (rm, "new-senders", G_CALLBACK (new_senders_cb), NULL); + + g_signal_connect (rm, "lost-senders", G_CALLBACK (lost_senders_cb), NULL); + + rmc_connected_handler = g_signal_connect (rmc, "connected", + G_CALLBACK (rmc_connected), NULL); + + g_signal_connect (rm, "connected", G_CALLBACK (rm_connected), NULL); + + g_signal_connect (rm, "disconnected", G_CALLBACK (rm_disconnected), NULL); + + /* test transport starts out connected */ + g_assert (gibber_r_multicast_causal_transport_connect (rmc, FALSE, NULL)); + + io = g_io_channel_unix_new (STDIN_FILENO); + g_io_add_watch (io, G_IO_IN, got_input, NULL); + g_io_add_watch (io, G_IO_HUP|G_IO_ERR, got_error, NULL); + + g_main_loop_run (loop); + + return 0; +} diff --git a/lib/gibber/tests/test-resolver.c b/lib/gibber/tests/test-resolver.c new file mode 100644 index 00000000..bb6ab8d7 --- /dev/null +++ b/lib/gibber/tests/test-resolver.c @@ -0,0 +1,113 @@ +/* + * test-resolver.c - Source for TestResolver + * Copyright (C) 2008 Collabora Ltd. + * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include <stdio.h> +#include <stdlib.h> + +#include "test-resolver.h" + +G_DEFINE_TYPE(TestResolver, test_resolver, GIBBER_TYPE_RESOLVER) + +/* private structure */ +typedef struct _TestResolverPrivate TestResolverPrivate; + +struct _TestResolverPrivate +{ + gboolean dispose_has_run; +}; + +#define TEST_RESOLVER_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), TEST_TYPE_RESOLVER, TestResolverPrivate)) + +static void +test_resolver_init (TestResolver *obj) +{ +} + +static void test_resolver_dispose (GObject *object); +static void test_resolver_finalize (GObject *object); + +static gboolean test_resolv_srv (GibberResolver *resolver, guint id, + const gchar *service_name, const char *service, + GibberResolverServiceType type); + +static void +test_resolver_class_init (TestResolverClass *test_resolver_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (test_resolver_class); + GibberResolverClass *resolver_class = GIBBER_RESOLVER_CLASS + (test_resolver_class); + + g_type_class_add_private (test_resolver_class, sizeof (TestResolverPrivate)); + + object_class->dispose = test_resolver_dispose; + object_class->finalize = test_resolver_finalize; + + resolver_class->resolv_srv = test_resolv_srv; +} + +void +test_resolver_dispose (GObject *object) +{ + TestResolver *self = TEST_RESOLVER (object); + TestResolverPrivate *priv = TEST_RESOLVER_GET_PRIVATE (self); + + if (priv->dispose_has_run) + return; + + priv->dispose_has_run = TRUE; + + /* release any references held by the object here */ + + if (G_OBJECT_CLASS (test_resolver_parent_class)->dispose) + G_OBJECT_CLASS (test_resolver_parent_class)->dispose (object); +} + +void +test_resolver_finalize (GObject *object) +{ + G_OBJECT_CLASS (test_resolver_parent_class)->finalize (object); +} + + +static gboolean test_resolv_srv (GibberResolver *resolver, guint id, + const gchar *service_name, const char *service, + GibberResolverServiceType type) +{ + GList *entries = NULL; + int i; + + for (i = 0 ; i < 20 ; i++) + { + gchar *str; + + str = g_strdup_printf ("test%2d.example.com", i); + + entries = g_list_prepend (entries, + gibber_resolver_srv_record_new (str, 1234, + 10 - (i / 5) , 4 - i % 5)); + + g_free (str); + } + + gibber_resolver_srv_result (resolver, id, entries, NULL); + return FALSE; +} diff --git a/lib/gibber/tests/test-resolver.h b/lib/gibber/tests/test-resolver.h new file mode 100644 index 00000000..1d39e4e6 --- /dev/null +++ b/lib/gibber/tests/test-resolver.h @@ -0,0 +1,59 @@ +/* + * test-resolver.h - Header for TestResolver + * Copyright (C) 2008 Collabora Ltd. + * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __TEST_RESOLVER_H__ +#define __TEST_RESOLVER_H__ + +#include <glib-object.h> +#include <gibber/gibber-resolver.h> + +G_BEGIN_DECLS + +typedef struct _TestResolver TestResolver; +typedef struct _TestResolverClass TestResolverClass; + +struct _TestResolverClass { + GibberResolverClass parent_class; +}; + +struct _TestResolver { + GibberResolver parent; +}; + +GType test_resolver_get_type (void); + +/* TYPE MACROS */ +#define TEST_TYPE_RESOLVER \ + (test_resolver_get_type ()) +#define TEST_RESOLVER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), TEST_TYPE_RESOLVER, TestResolver)) +#define TEST_RESOLVER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), TEST_TYPE_RESOLVER, TestResolverClass)) +#define TEST_IS_RESOLVER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), TEST_TYPE_RESOLVER)) +#define TEST_IS_RESOLVER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), TEST_TYPE_RESOLVER)) +#define TEST_RESOLVER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_RESOLVER, TestResolverClass)) + + +G_END_DECLS + +#endif /* #ifndef __TEST_RESOLVER_H__*/ diff --git a/lib/gibber/tests/test-sasl-auth-server-signals-marshal.list b/lib/gibber/tests/test-sasl-auth-server-signals-marshal.list new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/lib/gibber/tests/test-sasl-auth-server-signals-marshal.list diff --git a/lib/gibber/tests/test-sasl-auth-server.c b/lib/gibber/tests/test-sasl-auth-server.c new file mode 100644 index 00000000..7132122e --- /dev/null +++ b/lib/gibber/tests/test-sasl-auth-server.c @@ -0,0 +1,460 @@ +/* + * test-sasl-auth-server.c - Source for TestSaslAuthServer + * Copyright (C) 2006 Collabora Ltd. + * @author Sjoerd Simons <sjoerd@luon.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "test-sasl-auth-server.h" + +#include <gibber/gibber-xmpp-stanza.h> +#include <gibber/gibber-xmpp-connection.h> +#include <gibber/gibber-transport.h> + +#include <gibber/gibber-namespaces.h> + +#include <sasl/sasl.h> + +#define CHECK_SASL_RETURN(x) \ +G_STMT_START { \ + if (x < SASL_OK) { \ + fprintf (stderr, "sasl error (%d): %s\n", \ + ret, sasl_errdetail (priv->sasl_conn)); \ + g_assert_not_reached (); \ + } \ +} G_STMT_END + +G_DEFINE_TYPE(TestSaslAuthServer, test_sasl_auth_server, G_TYPE_OBJECT) + +#if 0 +/* signal enum */ +enum +{ + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = {0}; +#endif + +typedef enum { + AUTH_STATE_STARTED, + AUTH_STATE_CHALLENGE, + AUTH_STATE_FINAL_CHALLENGE, + AUTH_STATE_AUTHENTICATED, +} AuthState; + +/* private structure */ +typedef struct _TestSaslAuthServerPrivate TestSaslAuthServerPrivate; + +struct _TestSaslAuthServerPrivate +{ + gboolean dispose_has_run; + GibberXmppConnection *conn; + sasl_conn_t *sasl_conn; + gchar *username; + gchar *password; + gchar *mech; + AuthState state; + ServerProblem problem; +}; + +#define TEST_SASL_AUTH_SERVER_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), TEST_TYPE_SASL_AUTH_SERVER, \ + TestSaslAuthServerPrivate)) + +static void +test_sasl_auth_server_init (TestSaslAuthServer *obj) +{ + TestSaslAuthServerPrivate *priv = TEST_SASL_AUTH_SERVER_GET_PRIVATE (obj); + priv->username = NULL; + priv->password = NULL; + priv->mech = NULL; + priv->state = AUTH_STATE_STARTED; + + /* allocate any data required by the object here */ +} + +static void test_sasl_auth_server_dispose (GObject *object); +static void test_sasl_auth_server_finalize (GObject *object); + +static void +test_sasl_auth_server_class_init ( + TestSaslAuthServerClass *test_sasl_auth_server_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (test_sasl_auth_server_class); + + g_type_class_add_private (test_sasl_auth_server_class, + sizeof (TestSaslAuthServerPrivate)); + + object_class->dispose = test_sasl_auth_server_dispose; + object_class->finalize = test_sasl_auth_server_finalize; + +} + +void +test_sasl_auth_server_dispose (GObject *object) +{ + TestSaslAuthServer *self = TEST_SASL_AUTH_SERVER (object); + TestSaslAuthServerPrivate *priv = TEST_SASL_AUTH_SERVER_GET_PRIVATE (self); + + if (priv->dispose_has_run) + return; + + priv->dispose_has_run = TRUE; + + /* release any references held by the object here */ + g_object_unref (priv->conn); + + if (G_OBJECT_CLASS (test_sasl_auth_server_parent_class)->dispose) + G_OBJECT_CLASS (test_sasl_auth_server_parent_class)->dispose (object); +} + +void +test_sasl_auth_server_finalize (GObject *object) +{ + TestSaslAuthServer *self = TEST_SASL_AUTH_SERVER (object); + TestSaslAuthServerPrivate *priv = TEST_SASL_AUTH_SERVER_GET_PRIVATE (self); + + /* free any data held directly by the object here */ + g_free (priv->username); + g_free (priv->password); + g_free (priv->mech); + + G_OBJECT_CLASS (test_sasl_auth_server_parent_class)->finalize (object); +} + +static void +parse_error (GibberXmppConnection *connection, gpointer user_data) +{ + fprintf (stderr, "PARSING FAILED IN SASL SERVER\n"); + g_assert_not_reached (); +} + +static void +stream_opened (GibberXmppConnection *connection, const gchar *to, + const gchar *from, const gchar *version, gpointer user_data) +{ + TestSaslAuthServer *self = TEST_SASL_AUTH_SERVER(user_data); + TestSaslAuthServerPrivate * priv = TEST_SASL_AUTH_SERVER_GET_PRIVATE (self); + GibberXmppStanza *stanza; + GibberXmppNode *mechnode = NULL; + + gibber_xmpp_connection_open (connection, NULL, "testserver", "1.0"); + /* Send stream features */ + stanza = gibber_xmpp_stanza_new ("features"); + gibber_xmpp_node_set_ns (stanza->node, GIBBER_XMPP_NS_STREAM); + + if (priv->problem != SERVER_PROBLEM_NO_SASL) + { + mechnode = gibber_xmpp_node_add_child_ns (stanza->node, + "mechanisms", GIBBER_XMPP_NS_SASL_AUTH); + if (priv->problem == SERVER_PROBLEM_NO_MECHANISMS) + { + /* lalala */ + } + else if (priv->mech != NULL) + { + gibber_xmpp_node_add_child_with_content (mechnode, "mechanism", + priv->mech); + } + else + { + const gchar *mechs; + gchar **mechlist; + gchar **tmp; + int ret; + ret = sasl_listmech (priv->sasl_conn, NULL, "","\n","", &mechs, + NULL,NULL); + CHECK_SASL_RETURN (ret); + mechlist = g_strsplit (mechs, "\n", -1); + for (tmp = mechlist; *tmp != NULL; tmp++) + { + gibber_xmpp_node_add_child_with_content (mechnode, + "mechanism", *tmp); + } + g_strfreev (mechlist); + } + } + + g_assert (gibber_xmpp_connection_send (connection, stanza, NULL)); + g_object_unref (stanza); +} + +static void +stream_closed (GibberXmppConnection *connection, gpointer user_data) +{ + gibber_xmpp_connection_close (connection); +} + +static void +auth_succeeded (TestSaslAuthServer *self) +{ + TestSaslAuthServerPrivate * priv = TEST_SASL_AUTH_SERVER_GET_PRIVATE(self); + GibberXmppStanza *s; + + g_assert (priv->state < AUTH_STATE_AUTHENTICATED); + priv->state = AUTH_STATE_AUTHENTICATED; + + s = gibber_xmpp_stanza_new ("success"); + gibber_xmpp_node_set_ns (s->node, GIBBER_XMPP_NS_SASL_AUTH); + + /* As a result of how the test works, sending out the success will cause the + * reopening of the stream, so we need to restart the connection first! */ + gibber_xmpp_connection_restart (priv->conn); + + g_assert (gibber_xmpp_connection_send (priv->conn, s, NULL)); + + g_object_unref (s); +} + +static void +handle_auth (TestSaslAuthServer *self, GibberXmppStanza *stanza) +{ + TestSaslAuthServerPrivate *priv = TEST_SASL_AUTH_SERVER_GET_PRIVATE (self); + const gchar *mech = gibber_xmpp_node_get_attribute (stanza->node, + "mechanism"); + guchar *response = NULL; + const gchar *challenge; + unsigned challenge_len; + gsize response_len = 0; + int ret; + + if (stanza->node->content != NULL) + { + response = g_base64_decode (stanza->node->content, &response_len); + } + + g_assert (priv->state == AUTH_STATE_STARTED); + priv->state = AUTH_STATE_CHALLENGE; + + + ret = sasl_server_start (priv->sasl_conn, mech, (gchar *) response, + (unsigned) response_len, &challenge, &challenge_len); + + CHECK_SASL_RETURN (ret); + if (challenge_len > 0) + { + GibberXmppStanza *c; + gchar *challenge64; + + if (ret == SASL_OK) + { + priv->state = AUTH_STATE_FINAL_CHALLENGE; + } + + challenge64 = g_base64_encode ((guchar *) challenge, challenge_len); + + c = gibber_xmpp_stanza_new ("challenge"); + gibber_xmpp_node_set_ns (c->node, GIBBER_XMPP_NS_SASL_AUTH); + gibber_xmpp_node_set_content (c->node, challenge64); + g_assert (gibber_xmpp_connection_send (priv->conn, c, NULL)); + g_object_unref (c); + + g_free (challenge64); + } + else if (ret == SASL_OK) + { + auth_succeeded (self); + } + else + { + g_assert_not_reached (); + } + + g_free (response); +} + +static void +handle_response (TestSaslAuthServer *self, GibberXmppStanza *stanza) +{ + TestSaslAuthServerPrivate * priv = TEST_SASL_AUTH_SERVER_GET_PRIVATE (self); + guchar *response = NULL; + const gchar *challenge; + unsigned challenge_len; + gsize response_len = 0; + int ret; + + + if (priv->state == AUTH_STATE_FINAL_CHALLENGE) + { + g_assert (stanza->node->content == NULL); + auth_succeeded (self); + return; + } + + g_assert (priv->state == AUTH_STATE_CHALLENGE); + + if (stanza->node->content != NULL) + { + response = g_base64_decode (stanza->node->content, &response_len); + } + + ret = sasl_server_step (priv->sasl_conn, (gchar *) response, + (unsigned) response_len, &challenge, &challenge_len); + + CHECK_SASL_RETURN (ret); + + if (challenge_len > 0) + { + GibberXmppStanza *c; + gchar *challenge64; + + if (ret == SASL_OK) + { + priv->state = AUTH_STATE_FINAL_CHALLENGE; + } + + challenge64 = g_base64_encode ((guchar *) challenge, challenge_len); + + c = gibber_xmpp_stanza_new ("challenge"); + gibber_xmpp_node_set_ns (c->node, GIBBER_XMPP_NS_SASL_AUTH); + gibber_xmpp_node_set_content (c->node, challenge64); + g_assert (gibber_xmpp_connection_send (priv->conn, c, NULL)); + g_object_unref (c); + + g_free (challenge64); + } + else if (ret == SASL_OK) + { + auth_succeeded (self); + } + else + { + g_assert_not_reached (); + } + + g_free (response); +} + +#define HANDLE(x) { #x, handle_##x } +static void +received_stanza (GibberXmppConnection *connection, GibberXmppStanza *stanza, + gpointer user_data) +{ + TestSaslAuthServer *self = TEST_SASL_AUTH_SERVER (user_data); + int i; + struct { + const gchar *name; + void (*func)(TestSaslAuthServer *self, GibberXmppStanza *stanza); + } handlers[] = { HANDLE(auth), HANDLE(response) }; + + if (strcmp (gibber_xmpp_node_get_ns (stanza->node), + GIBBER_XMPP_NS_SASL_AUTH)) + { + g_assert_not_reached (); + } + + for (i = 0 ; handlers[i].name != NULL; i++) + { + if (!strcmp (stanza->node->name, handlers[i].name)) + { + handlers[i].func (self, stanza); + return; + } + } + + g_assert_not_reached (); +} + +static int +test_sasl_server_auth_log (void *context, int level, const gchar *message) +{ + return SASL_OK; +} + +static int +test_sasl_server_auth_getopt (void *context, const char *plugin_name, + const gchar *option, const gchar **result, guint *len) +{ + int i; + static const struct { + const gchar *name; + const gchar *value; + } options[] = { + { "auxprop_plugin", "sasldb"}, + { "sasldb_path", "./sasl-test.db"}, + { NULL, NULL }, + }; + + for (i = 0; options[i].name != NULL; i++) + { + if (!strcmp (option, options[i].name)) + { + *result = options[i].value; + if (len != NULL) + *len = strlen (options[i].value); + } + } + + return SASL_OK; +} + +TestSaslAuthServer * +test_sasl_auth_server_new (GibberTransport *transport, gchar *mech, + const gchar *user, const gchar *password, ServerProblem problem) +{ + TestSaslAuthServer *server; + TestSaslAuthServerPrivate *priv; + static gboolean sasl_initialized = FALSE; + int ret; + static sasl_callback_t callbacks[] = { + { SASL_CB_LOG, test_sasl_server_auth_log, NULL }, + { SASL_CB_GETOPT, test_sasl_server_auth_getopt, NULL }, + { SASL_CB_LIST_END, NULL, NULL }, + }; + + if (!sasl_initialized) + { + sasl_server_init (NULL, NULL); + sasl_initialized = TRUE; + } + + server = g_object_new (TEST_TYPE_SASL_AUTH_SERVER, NULL); + priv = TEST_SASL_AUTH_SERVER_GET_PRIVATE (server); + + priv->state = AUTH_STATE_STARTED; + + ret = sasl_server_new ("xmpp", NULL, NULL, NULL, NULL, callbacks, + SASL_SUCCESS_DATA, &(priv->sasl_conn)); + CHECK_SASL_RETURN (ret); + + ret = sasl_setpass (priv->sasl_conn, user, password, strlen (password), + NULL, 0, SASL_SET_CREATE); + + CHECK_SASL_RETURN (ret); + + priv->username = g_strdup (user); + priv->password = g_strdup (password); + priv->mech = g_strdup (mech); + priv->problem = problem; + + priv->conn = gibber_xmpp_connection_new (transport); + g_signal_connect (priv->conn, "parse-error", + G_CALLBACK (parse_error), server); + g_signal_connect (priv->conn, "stream-opened", + G_CALLBACK (stream_opened), server); + g_signal_connect (priv->conn, "stream-closed", + G_CALLBACK (stream_closed), server); + g_signal_connect (priv->conn, "received-stanza", + G_CALLBACK (received_stanza), server); + + return server; +} diff --git a/lib/gibber/tests/test-sasl-auth-server.h b/lib/gibber/tests/test-sasl-auth-server.h new file mode 100644 index 00000000..cbfe95ea --- /dev/null +++ b/lib/gibber/tests/test-sasl-auth-server.h @@ -0,0 +1,73 @@ +/* + * test-sasl-auth-server.h - Header for TestSaslAuthServer + * Copyright (C) 2006 Collabora Ltd. + * @author Sjoerd Simons <sjoerd@luon.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __TEST_SASL_AUTH_SERVER_H__ +#define __TEST_SASL_AUTH_SERVER_H__ + +#include <glib-object.h> + +#include <gibber/gibber-transport.h> + +G_BEGIN_DECLS + +typedef enum { + SERVER_PROBLEM_NO_PROBLEM, + SERVER_PROBLEM_NO_SASL, + SERVER_PROBLEM_NO_MECHANISMS, +} ServerProblem; + +typedef struct _TestSaslAuthServer TestSaslAuthServer; +typedef struct _TestSaslAuthServerClass TestSaslAuthServerClass; + +struct _TestSaslAuthServerClass { + GObjectClass parent_class; +}; + +struct _TestSaslAuthServer { + GObject parent; +}; + +GType test_sasl_auth_server_get_type (void); + +/* TYPE MACROS */ +#define TEST_TYPE_SASL_AUTH_SERVER \ + (test_sasl_auth_server_get_type ()) +#define TEST_SASL_AUTH_SERVER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), TEST_TYPE_SASL_AUTH_SERVER, \ + TestSaslAuthServer)) +#define TEST_SASL_AUTH_SERVER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), TEST_TYPE_SASL_AUTH_SERVER, \ + TestSaslAuthServerClass)) +#define TEST_IS_SASL_AUTH_SERVER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), TEST_TYPE_SASL_AUTH_SERVER)) +#define TEST_IS_SASL_AUTH_SERVER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), TEST_TYPE_SASL_AUTH_SERVER)) +#define TEST_SASL_AUTH_SERVER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_SASL_AUTH_SERVER, \ + TestSaslAuthServerClass)) + + +TestSaslAuthServer * test_sasl_auth_server_new (GibberTransport *transport, + gchar *mech, const gchar *user, const gchar *password, + ServerProblem problem); + +G_END_DECLS + +#endif /* #ifndef __TEST_SASL_AUTH_SERVER_H__*/ diff --git a/lib/gibber/tests/test-transport.c b/lib/gibber/tests/test-transport.c new file mode 100644 index 00000000..78bd5660 --- /dev/null +++ b/lib/gibber/tests/test-transport.c @@ -0,0 +1,209 @@ +/* + * test-transport.c - Source for TestTransport + * Copyright (C) 2006 Collabora Ltd. + * @author Sjoerd Simons <sjoerd@luon.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include <stdio.h> +#include <stdlib.h> + +#include "test-transport.h" + +static gboolean +test_transport_send (GibberTransport *transport, const guint8 *data, + gsize size, GError **error); + +void test_transport_disconnect (GibberTransport *transport); + +G_DEFINE_TYPE (TestTransport, test_transport, GIBBER_TYPE_TRANSPORT) + +/* private structure */ +typedef struct _TestTransportPrivate TestTransportPrivate; + +struct _TestTransportPrivate +{ + gboolean dispose_has_run; + test_transport_send_hook send; + GQueue *buffers; + guint send_id; + gpointer user_data; + + gboolean echoing; +}; + +#define TEST_TRANSPORT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ + TEST_TYPE_TRANSPORT, TestTransportPrivate)) + +static void +test_transport_init (TestTransport *obj) +{ + TestTransportPrivate *priv = TEST_TRANSPORT_GET_PRIVATE (obj); + + /* allocate any data required by the object here */ + priv->send = NULL; + priv->buffers = g_queue_new (); + priv->send_id = 0; +} + +static void test_transport_dispose (GObject *object); +static void test_transport_finalize (GObject *object); + +static void +test_transport_class_init (TestTransportClass *test_transport_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (test_transport_class); + GibberTransportClass *transport_class = + GIBBER_TRANSPORT_CLASS(test_transport_class); + + g_type_class_add_private (test_transport_class, sizeof (TestTransportPrivate)); + + object_class->dispose = test_transport_dispose; + object_class->finalize = test_transport_finalize; + + transport_class->send = test_transport_send; + transport_class->disconnect = test_transport_disconnect; +} + +void +test_transport_dispose (GObject *object) +{ + TestTransport *self = TEST_TRANSPORT (object); + TestTransportPrivate *priv = TEST_TRANSPORT_GET_PRIVATE (self); + + if (priv->dispose_has_run) + return; + + if (priv->send_id != 0) + g_source_remove (priv->send_id); + + priv->dispose_has_run = TRUE; + + /* release any references held by the object here */ + + if (G_OBJECT_CLASS (test_transport_parent_class)->dispose) + G_OBJECT_CLASS (test_transport_parent_class)->dispose (object); +} + +static void +free_array (gpointer data, gpointer user_data) +{ + g_array_free ((GArray *) data, TRUE); +} + +void +test_transport_finalize (GObject *object) +{ + TestTransport *self = TEST_TRANSPORT (object); + TestTransportPrivate *priv = TEST_TRANSPORT_GET_PRIVATE (self); + + /* free any data held directly by the object here */ + g_queue_foreach (priv->buffers, free_array, NULL); + g_queue_free (priv->buffers); + G_OBJECT_CLASS (test_transport_parent_class)->finalize (object); +} + +static gboolean +send_data (gpointer data) +{ + TestTransport *self = TEST_TRANSPORT (data); + TestTransportPrivate *priv = TEST_TRANSPORT_GET_PRIVATE (self); + GArray *arr; + + g_assert (priv->send != NULL); + + arr = (GArray *) g_queue_pop_head (priv->buffers); + + priv->send (GIBBER_TRANSPORT (self), + (guint8 *) arr->data, arr->len, NULL, priv->user_data); + + g_array_free (arr, TRUE); + + if (g_queue_is_empty (priv->buffers)) + { + priv->send_id = 0; + return FALSE; + } + + return TRUE; +} + +static gboolean +test_transport_send (GibberTransport *transport, + const guint8 *data, gsize size, GError **error) +{ + TestTransport *self = TEST_TRANSPORT (transport); + TestTransportPrivate *priv = TEST_TRANSPORT_GET_PRIVATE (self); + + GArray *arr; + + if (priv->echoing) + { + test_transport_write (self, data, size); + } + + arr = g_array_sized_new (FALSE, TRUE, sizeof (guint8), size); + g_array_append_vals (arr, data, size); + + g_queue_push_tail (priv->buffers, arr); + + if (priv->send_id == 0) + { + priv->send_id = g_idle_add (send_data, transport); + } + + return TRUE; +} + +void +test_transport_disconnect (GibberTransport *transport) +{ + gibber_transport_set_state (GIBBER_TRANSPORT(transport), + GIBBER_TRANSPORT_DISCONNECTED); +} + + +TestTransport * +test_transport_new (test_transport_send_hook send_, gpointer user_data) +{ + TestTransport *self; + TestTransportPrivate *priv; + + self = g_object_new (TEST_TYPE_TRANSPORT, NULL); + priv = TEST_TRANSPORT_GET_PRIVATE (self); + priv->send = send_; + priv->user_data = user_data; + + gibber_transport_set_state (GIBBER_TRANSPORT(self), + GIBBER_TRANSPORT_CONNECTED); + + return self; +} + +void +test_transport_set_echoing (TestTransport *transport, gboolean echo) +{ + TestTransportPrivate *priv = TEST_TRANSPORT_GET_PRIVATE (transport); + priv->echoing = echo; +} + + +void +test_transport_write (TestTransport *transport, const guint8 *buf, gsize size) +{ + gibber_transport_received_data (GIBBER_TRANSPORT (transport), buf, size); +} diff --git a/lib/gibber/tests/test-transport.h b/lib/gibber/tests/test-transport.h new file mode 100644 index 00000000..1e76d133 --- /dev/null +++ b/lib/gibber/tests/test-transport.h @@ -0,0 +1,73 @@ +/* + * test-transport.h - Header for TestTransport + * Copyright (C) 2006 Collabora Ltd. + * @author Sjoerd Simons <sjoerd@luon.net> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __TEST_TRANSPORT_H__ +#define __TEST_TRANSPORT_H__ + +#include <glib-object.h> + +#include <gibber/gibber-transport.h> + +G_BEGIN_DECLS + +typedef struct _TestTransport TestTransport; +typedef struct _TestTransportClass TestTransportClass; + +struct _TestTransportClass { + GibberTransportClass parent_class; +}; + +struct _TestTransport { + GibberTransport parent; +}; + +GType test_transport_get_type (void); + +/* TYPE MACROS */ +#define TEST_TYPE_TRANSPORT \ + (test_transport_get_type ()) +#define TEST_TRANSPORT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), TEST_TYPE_TRANSPORT, TestTransport)) +#define TEST_TRANSPORT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), TEST_TYPE_TRANSPORT, TestTransportClass)) +#define TEST_IS_TRANSPORT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), TEST_TYPE_TRANSPORT)) +#define TEST_IS_TRANSPORT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), TEST_TYPE_TRANSPORT)) +#define TEST_TRANSPORT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_TRANSPORT, TestTransportClass)) + +typedef gboolean (*test_transport_send_hook)(GibberTransport *transport, + const guint8 *data, + gsize length, + GError **error, + gpointer user_data); +TestTransport *test_transport_new (test_transport_send_hook send, + gpointer user_data); + +void test_transport_set_echoing (TestTransport *transport, + gboolean echo); + +void test_transport_write (TestTransport *transport, + const guint8 *buf, gsize size); + +G_END_DECLS + +#endif /* #ifndef __TEST_TRANSPORT_H__*/ diff --git a/lib/gibber/tests/test-xmpp-connection.c b/lib/gibber/tests/test-xmpp-connection.c new file mode 100644 index 00000000..71e5e2b1 --- /dev/null +++ b/lib/gibber/tests/test-xmpp-connection.c @@ -0,0 +1,157 @@ +#include <stdio.h> +#include <unistd.h> +#include <glib.h> + +#include <gibber/gibber-xmpp-connection.h> +#include <gibber/gibber-transport.h> +#include "test-transport.h" + +#define BUFSIZE 10 + +FILE *treefile = NULL; +FILE *xmlfile = NULL; +gboolean parsing_failed = FALSE; + +static gboolean +send_hook (GibberTransport *transport, const guint8 *data, + gsize length, GError **error, gpointer user_data) +{ + size_t written; + /* Nothing for now */ + written = fwrite (data, 1, length, xmlfile); + g_assert (written == length); + return TRUE; +} + +static void +parse_error (GibberXmppConnection *connection, gpointer user_data) +{ + fprintf (treefile, "PARSE ERROR\n"); + fprintf (stderr, "PARSING FAILED\n"); + parsing_failed = TRUE; +} + +static void +stream_opened (GibberXmppConnection *connection, const gchar *to, + const gchar *from, const gchar *version, gpointer user_data) +{ + fprintf (treefile, "STREAM OPENED to=%s from=%s version=%s\n", to, from, + version); + + gibber_xmpp_connection_open (connection, to, from, version); +} + +static void +stream_closed (GibberXmppConnection *connection, gpointer user_data) +{ + fprintf (treefile, "STREAM CLOSED\n"); + gibber_xmpp_connection_close (connection); +} + +static gboolean +print_attribute (const gchar *key, const gchar *value, const gchar *ns, + gpointer user_data) +{ + fprintf (treefile, "%*s |-- Attribute: %s -> %s (ns: %s)\n", + GPOINTER_TO_INT (user_data), " ", key, value, ns); + return TRUE; +} + +static void print_node (GibberXmppNode *node, gint ident); + +static gboolean +print_child (GibberXmppNode *node, gpointer user_data) +{ + print_node (node, GPOINTER_TO_INT(user_data)); + return TRUE; +} + +static void +print_node (GibberXmppNode *node, gint ident) +{ + fprintf (treefile, "%*s`-+-- Name: %s (ns: %s)\n", ident - 1, " ", + node->name, gibber_xmpp_node_get_ns (node)); + gibber_xmpp_node_each_attribute (node, print_attribute, + GINT_TO_POINTER(ident)); + + if (node->content) + fprintf (treefile, "%*s |-- Content: %s\n", ident, " ", node->content); + if (gibber_xmpp_node_get_language (node)) + fprintf (treefile, "%*s |-- Language: %s\n", ident, " ", + gibber_xmpp_node_get_language (node)); + + gibber_xmpp_node_each_child (node, print_child, GINT_TO_POINTER (ident + 2)); +} + +static void +received_stanza (GibberXmppConnection *connection, GibberXmppStanza *stanza, + gpointer user_data) +{ + fprintf (treefile, "-|\n"); + print_node (stanza->node, 2); + g_assert (gibber_xmpp_connection_send (connection, stanza, NULL)); +} + +int +main (int argc, char **argv) +{ + GibberXmppConnection *connection; + TestTransport *transport; + FILE *file; + int ret = 0; + guint8 buf[BUFSIZE]; + + + g_type_init (); + + transport = test_transport_new (send_hook, NULL); + connection = gibber_xmpp_connection_new (GIBBER_TRANSPORT(transport)); + + g_signal_connect (connection, "parse-error", + G_CALLBACK (parse_error), NULL); + g_signal_connect (connection, "stream-opened", + G_CALLBACK (stream_opened), NULL); + g_signal_connect (connection, "stream-closed", + G_CALLBACK (stream_closed), NULL); + g_signal_connect (connection, "received-stanza", + G_CALLBACK (received_stanza), NULL); + + g_assert (argc >= 2 && argc < 5); + + file = fopen (argv[1], "r"); + g_assert (file != NULL); + + if (argc >= 3) + { + treefile = fopen (argv[2], "w+"); + } + else + { + treefile = stdout; + } + g_assert (treefile != NULL); + + if (argc >= 4) + { + xmlfile = fopen (argv[3], "w+"); + } + else + { + xmlfile = stderr; + } + g_assert (xmlfile != NULL); + + while (!parsing_failed && (ret = fread (buf, 1, BUFSIZE, file)) > 0) + { + test_transport_write (transport, buf, ret); + } + + while (g_main_context_iteration (NULL, FALSE)) + ; + + + g_assert (parsing_failed || ret == 0); + fclose (file); + + return parsing_failed ? 1 : 0; +} |