Skip to content
Browse files

initial commit

  • Loading branch information...
0 parents commit a2243d1c11dd7a7bd7a19b40ef7e6b8a7fa3df4b @rstml rstml committed Dec 6, 2011
Showing with 21,594 additions and 0 deletions.
  1. +6 −0 .gitignore
  2. +278 −0 LICENSE
  3. +43 −0 README
  4. +67 −0 assembly/pom.xml
  5. +43 −0 assembly/src/main/etc/assembly/assembly.xml
  6. +26 −0 assembly/src/main/etc/bin/elasticinbox
  7. 0 bundles/com.ecyrd.speed4j/.gitignore
  8. +9 −0 bundles/com.ecyrd.speed4j/osgi.bnd
  9. +36 −0 bundles/com.ecyrd.speed4j/pom.xml
  10. +22 −0 bundles/pom.xml
  11. +41 −0 config/elasticinbox.cml
  12. +73 −0 config/elasticinbox.yaml
  13. +113 −0 config/jetty.xml
  14. +42 −0 config/logback.xml
  15. 0 itests/.gitignore
  16. +318 −0 itests/pom.xml
  17. +892 −0 itests/src/test/java/com/elasticinbox/itests/RestIT.java
  18. +4,069 −0 itests/src/test/resources/01-attach-utf8.eml
  19. +264 −0 itests/src/test/resources/01-headers-utf8.eml
  20. +50 −0 itests/src/test/resources/elasticinbox.yaml
  21. +14 −0 itests/src/test/resources/logback.xml
  22. +3 −0 modules/common/build.properties
  23. +9 −0 modules/common/osgi.bnd
  24. +87 −0 modules/common/pom.xml
  25. +35 −0 modules/common/src/main/java/com/elasticinbox/common/Disposable.java
  26. +53 −0 modules/common/src/main/java/com/elasticinbox/common/utils/Assert.java
  27. +126 −0 modules/common/src/main/java/com/elasticinbox/common/utils/IOUtils.java
  28. +111 −0 modules/common/src/main/java/com/elasticinbox/common/utils/JSONUtils.java
  29. +35 −0 modules/common/src/main/java/com/elasticinbox/common/utils/ThreadLocalByteBuffer.java
  30. 0 modules/common/src/main/resources/.gitignore
  31. +3 −0 modules/config/build.properties
  32. +10 −0 modules/config/osgi.bnd
  33. +80 −0 modules/config/pom.xml
  34. +55 −0 modules/config/src/main/java/com/elasticinbox/config/Config.java
  35. +33 −0 modules/config/src/main/java/com/elasticinbox/config/ConfigurationException.java
  36. +203 −0 modules/config/src/main/java/com/elasticinbox/config/Configurator.java
  37. +96 −0 modules/config/src/main/java/com/elasticinbox/config/blob/BlobStoreProfile.java
  38. 0 modules/config/src/main/resources/.gitignore
  39. +3 −0 modules/core/build.properties
  40. +28 −0 modules/core/osgi.bnd
  41. +294 −0 modules/core/pom.xml
  42. +52 −0 modules/core/src/main/java/com/elasticinbox/core/AccountDAO.java
  43. +52 −0 modules/core/src/main/java/com/elasticinbox/core/DAOFactory.java
  44. +34 −0 modules/core/src/main/java/com/elasticinbox/core/IllegalLabelException.java
  45. +89 −0 modules/core/src/main/java/com/elasticinbox/core/LabelDAO.java
  46. +219 −0 modules/core/src/main/java/com/elasticinbox/core/MessageDAO.java
  47. +34 −0 modules/core/src/main/java/com/elasticinbox/core/OverQuotaException.java
  48. +258 −0 modules/core/src/main/java/com/elasticinbox/core/blob/BlobProxy.java
  49. +43 −0 modules/core/src/main/java/com/elasticinbox/core/blob/naming/AbstractBlobNamingPolicy.java
  50. +63 −0 modules/core/src/main/java/com/elasticinbox/core/blob/naming/BlobNameBuilder.java
  51. +40 −0 modules/core/src/main/java/com/elasticinbox/core/blob/naming/UuidBlobNamingPolicy.java
  52. +62 −0 modules/core/src/main/java/com/elasticinbox/core/cassandra/AbstractMessageDAO.java
  53. +158 −0 modules/core/src/main/java/com/elasticinbox/core/cassandra/CassandraAccountDAO.java
  54. +108 −0 modules/core/src/main/java/com/elasticinbox/core/cassandra/CassandraDAOFactory.java
  55. +182 −0 modules/core/src/main/java/com/elasticinbox/core/cassandra/CassandraLabelDAO.java
  56. +466 −0 modules/core/src/main/java/com/elasticinbox/core/cassandra/CassandraMessageDAO.java
  57. +60 −0 modules/core/src/main/java/com/elasticinbox/core/cassandra/QuorumConsistencyLevel.java
  58. +60 −0 modules/core/src/main/java/com/elasticinbox/core/cassandra/Speed4jOpTimer.java
  59. +167 −0 modules/core/src/main/java/com/elasticinbox/core/cassandra/persistence/AccountPersistence.java
  60. +245 −0 modules/core/src/main/java/com/elasticinbox/core/cassandra/persistence/LabelCounterPersistence.java
  61. +199 −0 modules/core/src/main/java/com/elasticinbox/core/cassandra/persistence/LabelIndexPersistence.java
  62. +279 −0 modules/core/src/main/java/com/elasticinbox/core/cassandra/persistence/Marshaller.java
  63. +261 −0 modules/core/src/main/java/com/elasticinbox/core/cassandra/persistence/MessagePersistence.java
  64. +161 −0 modules/core/src/main/java/com/elasticinbox/core/cassandra/persistence/PurgeIndexPersistence.java
  65. +106 −0 modules/core/src/main/java/com/elasticinbox/core/log/JcloudsSlf4JLogger.java
  66. +37 −0 modules/core/src/main/java/com/elasticinbox/core/log/JcloudsSlf4JLoggingModule.java
  67. +335 −0 modules/core/src/main/java/com/elasticinbox/core/message/MimeParser.java
  68. +29 −0 modules/core/src/main/java/com/elasticinbox/core/message/MimeParserException.java
  69. +49 −0 modules/core/src/main/java/com/elasticinbox/core/message/id/AbstractMessageIdPolicy.java
  70. +63 −0 modules/core/src/main/java/com/elasticinbox/core/message/id/CurrentTimeMessageIdPolicy.java
  71. +78 −0 modules/core/src/main/java/com/elasticinbox/core/message/id/MessageIdBuilder.java
  72. +67 −0 modules/core/src/main/java/com/elasticinbox/core/message/id/SentDateMessageIdPolicy.java
  73. +84 −0 modules/core/src/main/java/com/elasticinbox/core/model/Address.java
  74. +77 −0 modules/core/src/main/java/com/elasticinbox/core/model/AddressList.java
  75. +55 −0 modules/core/src/main/java/com/elasticinbox/core/model/Label.java
  76. +77 −0 modules/core/src/main/java/com/elasticinbox/core/model/LabelCounters.java
  77. +175 −0 modules/core/src/main/java/com/elasticinbox/core/model/Labels.java
  78. +76 −0 modules/core/src/main/java/com/elasticinbox/core/model/Mailbox.java
  79. +91 −0 modules/core/src/main/java/com/elasticinbox/core/model/Marker.java
  80. +303 −0 modules/core/src/main/java/com/elasticinbox/core/model/Message.java
  81. +167 −0 modules/core/src/main/java/com/elasticinbox/core/model/MimePart.java
  82. +71 −0 modules/core/src/main/java/com/elasticinbox/core/model/ReservedLabels.java
  83. +44 −0 modules/core/src/main/java/com/elasticinbox/core/utils/LabelUtils.java
  84. 0 modules/core/src/main/resources/.gitignore
  85. +1 −0 modules/lmtp/README
  86. +3 −0 modules/lmtp/build.properties
  87. +11 −0 modules/lmtp/osgi.bnd
  88. +101 −0 modules/lmtp/pom.xml
  89. +116 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/Activator.java
  90. +56 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/LMTPProxyServer.java
  91. +48 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/delivery/DeliveryAction.java
  92. +45 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/delivery/DeliveryAgentFactory.java
  93. +180 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/delivery/ElasticInboxDeliveryAgent.java
  94. +93 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/delivery/ElasticInboxDeliveryBackend.java
  95. +23 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/delivery/IDeliveryAgent.java
  96. +27 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/delivery/IDeliveryBackend.java
  97. +293 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/LMTPServer.java
  98. +269 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/LMTPServerConfig.java
  99. +92 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/api/Blob.java
  100. +29 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/api/DeliveryException.java
  101. +461 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/api/LMTPAddress.java
  102. +52 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/api/LMTPBodyType.java
  103. +72 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/api/LMTPEnvelope.java
  104. +108 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/api/LMTPReply.java
  105. +40 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/api/RejectException.java
  106. +47 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/api/SessionContext.java
  107. +29 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/api/TooMuchDataException.java
  108. +122 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/api/handler/AbstractDeliveryHandler.java
  109. +55 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/api/handler/DefaultDeliveryHandler.java
  110. +31 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/api/handler/DeliveryContext.java
  111. +131 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/api/handler/ElasticInboxDeliveryHandler.java
  112. +125 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/AbstractBaseCommand.java
  113. +49 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/BuiltinCommandRegistry.java
  114. +21 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/Command.java
  115. +40 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/CommandException.java
  116. +144 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/CommandHandler.java
  117. +34 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/InvalidCommandNameException.java
  118. +34 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/UnknownCommandException.java
  119. +46 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/impl/DataCommand.java
  120. +48 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/impl/DataEndCommand.java
  121. +81 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/impl/HelpCommand.java
  122. +102 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/impl/HelpMessage.java
  123. +71 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/impl/LhloCommand.java
  124. +94 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/impl/MailCommand.java
  125. +30 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/impl/NoopCommand.java
  126. +31 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/impl/QuitCommand.java
  127. +74 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/impl/ReceiptCommand.java
  128. +37 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/impl/ResetCommand.java
  129. +35 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/command/impl/VerifyCommand.java
  130. +68 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/core/DeliveryHandlerFactory.java
  131. +84 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/core/Session.java
  132. +166 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/core/mina/CharTerminatedInputStream.java
  133. +98 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/core/mina/DotUnstuffingInputStream.java
  134. +230 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/core/mina/LMTPCodecDecoder.java
  135. +101 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/core/mina/LMTPCodecFactory.java
  136. +223 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/core/mina/LMTPConnectionHandler.java
  137. +60 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/core/mina/LMTPContext.java
  138. +219 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/server/core/mina/LMTPDecoderContext.java
  139. +575 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/utils/Base64.java
  140. +53 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/utils/LoggingPeriodicalLog.java
  141. +39 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/utils/MimeUtils.java
  142. +120 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/utils/SharedByteArrayInputStream.java
  143. +88 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/utils/SharedInputStream.java
  144. +54 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/utils/SharedStreamUtils.java
  145. +533 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/utils/SharedTmpFileInputStream.java
  146. +26 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/validator/DummyValidator.java
  147. +19 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/validator/IValidator.java
  148. +18 −0 modules/lmtp/src/main/java/com/elasticinbox/lmtp/validator/ValidatorFactory.java
  149. 0 modules/lmtp/src/main/resources/.gitignore
  150. +26 −0 modules/pom.xml
  151. +5 −0 modules/rest/build.properties
  152. +24 −0 modules/rest/osgi.bnd
  153. +168 −0 modules/rest/pom.xml
  154. +35 −0 modules/rest/src/main/java/com/elasticinbox/rest/BadRequestException.java
  155. +50 −0 modules/rest/src/main/java/com/elasticinbox/rest/CharsetResponseFilter.java
  156. +25 −0 modules/rest/src/main/java/com/elasticinbox/rest/JSONResponse.java
  157. +97 −0 modules/rest/src/main/java/com/elasticinbox/rest/WebAppContextListener.java
  158. +141 −0 modules/rest/src/main/java/com/elasticinbox/rest/v1/AccountResource.java
  159. +215 −0 modules/rest/src/main/java/com/elasticinbox/rest/v1/LabelResource.java
  160. +129 −0 modules/rest/src/main/java/com/elasticinbox/rest/v1/MailboxResource.java
  161. +259 −0 modules/rest/src/main/java/com/elasticinbox/rest/v1/MessageResource.java
  162. +475 −0 modules/rest/src/main/java/com/elasticinbox/rest/v1/SingleMessageResource.java
  163. 0 modules/rest/src/main/resources/.gitignore
  164. +33 −0 modules/rest/src/main/webapp/WEB-INF/web.xml
  165. +222 −0 pom.xml
  166. +61 −0 poms/compiled/pom.xml
  167. +117 −0 poms/pom.xml
  168. +56 −0 poms/wrappers/pom.xml
  169. +105 −0 provision/pom.xml
6 .gitignore
@@ -0,0 +1,6 @@
+/assembly/runner
+/runner
+target
+.settings
+.project
+.classpath
278 LICENSE
@@ -0,0 +1,278 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, 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.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, 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 or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+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 give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) 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; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, 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 executable. However, as a
+special exception, the source code 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+ 5. 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 Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program 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 to
+this License.
+
+ 7. 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 Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 Program
+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 Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, 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
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
43 README
@@ -0,0 +1,43 @@
+ElasticInbox is a scalable, distributed email store.
+See http://www.elasticinbox.com
+
+Description
+-----------
+Based on Apache Cassandra for metadata and Jclouds for blob store, ElasticInbox
+provides reliable, scalable and distributed email store without SPOF.
+
+Requirements
+------------
+ * Java >= 1.6
+ * Apache Cassandra >= 0.8.0 (see http://cassandra.apache.org/)
+
+Getting started
+---------------
+Download binary package. Make sure Cassandra is up and running.
+
+ % tar -zxf elasticinbox-0.2.0-SNAPSHOT-bin.tar.gz
+ % mkdir /var/log/elasticinbox
+
+Create keyspace ElasticInbox in your Cassandra cluster and load schema:
+
+ % cassandra-cli --host localhost < elasticinbox.cml
+
+Configure ElasticInbox:
+
+ % vi elasticinbox-0.2.0-SNAPSHOT/config/elasticinbox.yaml
+
+Optionally you can also change configuration for HTTP server (jetty.xml) and
+logger (logback.xml) in the same folder. By default, HTTP will be listening on
+port 8181.
+
+Run ElasticInbox:
+
+ % elasticinbox-0.2.0-SNAPSHOT/bin/elasticinbox
+
+Building from Source
+--------------------
+To build and run from source you will need Maven 3 and Git:
+
+ % git clone https://github.com/elasticinbox/elasticinbox elasticinbox
+ % cd elasticinbox
+ % mvn clean install pax:provision -DskipITs
67 assembly/pom.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <parent>
+ <relativePath>../poms/compiled/</relativePath>
+ <groupId>com.elasticinbox.parent.build</groupId>
+ <artifactId>compiled-bundle-settings</artifactId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.elasticinbox</groupId>
+ <artifactId>elasticinbox-assembly</artifactId>
+
+ <name>ElasticInbox Project - Assembly</name>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.ops4j</groupId>
+ <artifactId>maven-pax-plugin</artifactId>
+ <configuration>
+ <provision>
+ <param>--platform=${default.osgi.framework}</param>
+ <param>--version=${default.osgi.framework.version}</param>
+ <param>--profile=compendium,war</param>
+ <param>--bootDelegation=${boot.delegation.packages}</param>
+ <param>--executor=noop</param>
+ </provision>
+ </configuration>
+ <executions>
+ <execution>
+ <id>package-provision</id>
+ <phase>package</phase>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.2.1</version>
+ <executions>
+ <execution>
+ <id>package-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <appendAssemblyId>true</appendAssemblyId>
+ <finalName>elasticinbox-${project.version}</finalName>
+ <descriptors>
+ <descriptor>src/main/etc/assembly/assembly.xml</descriptor>
+ </descriptors>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
43 assembly/src/main/etc/assembly/assembly.xml
@@ -0,0 +1,43 @@
+<assembly
+ xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+
+ <id>bin</id>
+
+ <formats>
+ <format>tar.gz</format>
+ </formats>
+
+ <includeBaseDirectory>false</includeBaseDirectory>
+
+ <fileSets>
+ <fileSet>
+ <directory>${project.parent.parent.parent.basedir}/runner/bundles</directory>
+ <outputDirectory>/elasticinbox-${project.version}/lib/bundles</outputDirectory>
+ <includes>
+ <include>*.jar</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.parent.parent.parent.basedir}/runner/equinox</directory>
+ <outputDirectory>/elasticinbox-${project.version}/lib/equinox</outputDirectory>
+ <includes>
+ <include>*.ini</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+ <directory>${project.parent.parent.parent.basedir}/config</directory>
+ <outputDirectory>/elasticinbox-${project.version}/config</outputDirectory>
+ </fileSet>
+ </fileSets>
+
+ <files>
+ <file>
+ <source>src/main/etc/bin/elasticinbox</source>
+ <outputDirectory>/elasticinbox-${project.version}/bin</outputDirectory>
+ <fileMode>0777</fileMode>
+ </file>
+ </files>
+
+</assembly>
26 assembly/src/main/etc/bin/elasticinbox
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+curdir=`dirname $0`
+libdir="${curdir}/../lib"
+umask 066
+
+MEM=384
+TMP_DIR="/var/tmp"
+CONSOLE=""
+
+if [ "$1" == "console" ]; then
+ CONSOLE="-console -consoleLog"
+fi
+
+JVM_OPTS="-Xms${MEM}m -Xmx${MEM}m -Djava.io.tmpdir=${TMP_DIR}"
+
+# Uncomment to enable remote JMX access
+#JMX_OPTS="-Djava.net.preferIPv4Stack=true \
+#-Djava.rmi.server.hostname=10.0.0.1 \
+#-Dcom.sun.management.jmxremote \
+#-Dcom.sun.management.jmxremote.port=9099 \
+#-Dcom.sun.management.jmxremote.authenticate=false \
+#-Dcom.sun.management.jmxremote.ssl=false"
+
+cd ${libdir}
+exec /usr/bin/java ${JVM_OPTS} ${JMX_OPTS} -Dosgi.install.area=equinox -cp bundles/org.eclipse.osgi_3.6.2.R36x_v20110210.jar org.eclipse.core.runtime.adaptor.EclipseStarter ${CONSOLE} -configuration equinox
0 bundles/com.ecyrd.speed4j/.gitignore
No changes.
9 bundles/com.ecyrd.speed4j/osgi.bnd
@@ -0,0 +1,9 @@
+#--------------------------------------------------------------------------
+# Use this file to add customized Bnd instructions for the wrapped library
+#--------------------------------------------------------------------------
+
+#
+# this unpacks the contents of the wrapped jar artifact inside the bundle
+# to also inline dependencies of this artifact add Embed-Transitive: true
+#
+Embed-Dependency: *;scope=compile|runtime;type=!pom;inline=true
36 bundles/com.ecyrd.speed4j/pom.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <parent>
+ <relativePath>../../poms/wrappers/</relativePath>
+ <groupId>com.elasticinbox.parent.build</groupId>
+ <artifactId>wrapper-bundle-settings</artifactId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+
+ <properties>
+ <bundle.symbolicName>com.ecyrd.speed4j</bundle.symbolicName>
+ <wrapped.groupId>com.ecyrd.speed4j</wrapped.groupId>
+ <wrapped.artifactId>speed4j</wrapped.artifactId>
+ <wrapped.version>${bundle.speed4j.version}</wrapped.version>
+ </properties>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.elasticinbox.bundles</groupId>
+ <artifactId>com.ecyrd.speed4j</artifactId>
+ <version>${bundle.speed4j.version}-1</version>
+
+ <name>ElasticInbox Bundles :: ${wrapped.artifactId}</name>
+
+ <packaging>bundle</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>${wrapped.groupId}</groupId>
+ <artifactId>${wrapped.artifactId}</artifactId>
+ <version>${wrapped.version}</version>
+ <optional>true</optional>
+ </dependency>
+ </dependencies>
+
+</project>
22 bundles/pom.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <parent>
+ <groupId>com.elasticinbox</groupId>
+ <artifactId>elasticinbox-parent</artifactId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.elasticinbox.bundles</groupId>
+ <artifactId>elasticinbox-bundles</artifactId>
+
+ <name>ElasticInbox External Bundles</name>
+
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>com.ecyrd.speed4j</module>
+ </modules>
+
+</project>
41 config/elasticinbox.cml
@@ -0,0 +1,41 @@
+# ElasticInbox Schema v1.0
+#
+# To create schema, first you will need to create keyspace:
+#
+# create keyspace ElasticInbox
+# with placement_strategy = 'org.apache.cassandra.locator.SimpleStrategy'
+# and strategy_options = [{replication_factor:3}];
+#
+# After keyspace created you can copy paste text below, or simply run:
+#
+# % cassandra-cli --host 10.0.1.1 < elasticinbox.cml
+#
+
+use ElasticInbox;
+
+create column family Accounts with
+ key_validation_class=UTF8Type and
+ rows_cached=100000 and
+ comment='Basic information about accounts';
+
+create column family MessageMetadata with
+ column_type=Super and
+ key_validation_class=UTF8Type and
+ comparator=TimeUUIDType and
+ subcomparator=BytesType and
+ comment='Message metadata including headers, labels, markers, physical location, etc.';
+
+create column family IndexLabels with
+ key_validation_class=UTF8Type and
+ comparator=TimeUUIDType and
+ rows_cached=100000 and
+ comment='Message ID indexes grouped by labels and ordered by time';
+
+create column family Counters with
+ column_type=Super and
+ default_validation_class=CounterColumnType and
+ replicate_on_write=true and
+ key_validation_class=UTF8Type and
+ comparator=UTF8Type and
+ subcomparator=AsciiType and
+ comment='All counters for an account';
73 config/elasticinbox.yaml
@@ -0,0 +1,73 @@
+### ElasticInbox config file
+
+### Mailbox settings
+# Mailbox quota can be set by total bytes and/or message count.
+# To disable quota parameter set it to 0.
+mailbox_quota_bytes: 1073741824
+mailbox_quota_count: 50000
+
+### Monitoring settings
+# Enabling performance counters will allow monitoring of various stats
+# (e.g. LMTP, Hector) through the JMX interface.
+#
+# Stats are collected and aggregated for the given interval (in seconds).
+enable_performance_counters: true
+performance_counters_interval: 180
+
+### LMTP daemon settings
+# Set port number and maximum concurrent connections.
+lmtp_port: 2400
+lmtp_max_connections: 20
+
+### Metadata storage driver
+# currently only "cassandra" supported
+metadata_storage_driver: cassandra
+
+# If you want to store parsed HTML and/or PLAIN text of the message body
+# in the metadata storage, enable below.
+#
+# Note: When no HTML message body available in HTML store mode, ElasticInbox
+# will automatically fallback to PLAIN text mode and store available PLAIN text.
+store_html_message: true
+store_plain_message: false
+
+### Cassandra settings
+# Specify Cassandra hosts (multiple for LB), cluster name, keyspace
+# and auto discovery
+cassandra_hosts:
+ - 127.0.0.1:9160
+# - 127.0.0.2:9160
+# - 127.0.0.3:9160
+cassandra_autodiscovery: false
+cassandra_cluster_name: 'TestCluster'
+cassandra_keyspace: 'ElasticInbox'
+
+### Blob storage settings
+#
+# Following public and private blob store providers are supported:
+# aws-s3, cloudfiles-us, cloudfiles-uk, filesystem,
+# azureblob, atmos (generic), synaptic-storage, scaleup-storage,
+# cloudonestorage, walrus(generic), googlestorage, ninefold-storage,
+# scality-rs2 (generic), hosteurope-storage, tiscali-storage,
+# eucalyptus-partnercloud-s3, swift (generic)
+#
+# IMPORTANT: Blob store profile names should never be changed and should be
+# identical on all ElasticInbox nodes. Profile names are stored in
+# metadata. ElasticInbox does not verify profile configurations.
+#
+blobstore_profiles:
+ openstack-local:
+ provider: swift
+ endpoint: http://127.0.0.1:8080/auth/
+ container: elasticinbox
+ identity: elasticinbox:admin
+ credential: adm123
+ apiversion: 1.0
+ fs-local:
+ provider: filesystem
+ basedir: /u02/domains
+ container: elasticinbox
+
+# deafult profile to use for writing messages to blob storage
+# only one profile can be used for writing at the same time
+blobstore_write_profile: fs-local
113 config/jetty.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
+
+<!-- =============================================================== -->
+<!-- Configure the Jetty Server -->
+<!-- -->
+<!-- Documentation of this file format can be found at: -->
+<!-- http://docs.codehaus.org/display/JETTY/jetty.xml -->
+<!-- -->
+<!-- =============================================================== -->
+
+
+<Configure id="Server" class="org.eclipse.jetty.server.Server">
+
+ <!-- ============================================================================ -->
+ <!-- To correctly start Jetty with JMX module enabled, this configuration -->
+ <!-- file must appear first in the list of the configuration files. -->
+ <!-- The simplest way to achieve this is to add etc/jetty-jmx.xml as the -->
+ <!-- first file in configuration file list at the end of start.ini file. -->
+ <!-- ============================================================================ -->
+
+ <!-- =========================================================== -->
+ <!-- Initialize an mbean server -->
+ <!-- =========================================================== -->
+ <Call id="MBeanServer" class="java.lang.management.ManagementFactory" name="getPlatformMBeanServer" />
+
+ <!-- =========================================================== -->
+ <!-- Initialize the Jetty MBean container -->
+ <!-- =========================================================== -->
+ <New id="MBeanContainer" class="org.eclipse.jetty.jmx.MBeanContainer">
+ <Arg>
+ <Ref id="MBeanServer" />
+ </Arg>
+ </New>
+
+ <!-- Add to the Server to listen for object events -->
+ <Get id="Container" name="container">
+ <Call name="addEventListener">
+ <Arg>
+ <Ref id="MBeanContainer" />
+ </Arg>
+ </Call>
+ </Get>
+
+ <!-- =========================================================== -->
+ <!-- Server Thread Pool -->
+ <!-- =========================================================== -->
+ <Set name="ThreadPool">
+ <!-- Default queued blocking threadpool -->
+ <New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
+ <Set name="minThreads">10</Set>
+ <Set name="maxThreads">50</Set>
+ </New>
+
+ <!-- Optional Java 5 bounded threadpool with job queue
+ <New class="org.eclipse.jetty.util.thread.ExecutorThreadPool">
+ <Arg name="coreSize" type="int">25</Arg>
+ <Arg name="maxSize" type="int">50</Arg>
+ <Arg name="maxIdleMs" type="long">30000</Arg>
+ </New>
+ -->
+ </Set>
+
+ <!-- =========================================================== -->
+ <!-- Set connectors -->
+ <!-- =========================================================== -->
+
+ <Call name="addConnector">
+ <Arg>
+ <New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
+ <Set name="host"><Property name="jetty.host" /></Set>
+ <Set name="port"><Property name="jetty.port" default="8181"/></Set>
+ <Set name="maxIdleTime">300000</Set>
+ <Set name="Acceptors">2</Set>
+ <Set name="statsOn">true</Set>
+ <Set name="confidentialPort">8443</Set>
+ <Set name="lowResourcesConnections">20000</Set>
+ <Set name="lowResourcesMaxIdleTime">5000</Set>
+ </New>
+ </Arg>
+ </Call>
+
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+ <!-- To add a HTTPS SSL connector -->
+ <!-- mixin jetty-ssl.xml: -->
+ <!-- java -jar start.jar etc/jetty.xml etc/jetty-ssl.xml -->
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+ <!--
+ <Call name="addConnector">
+ <Arg>
+ <New class="org.eclipse.jetty.server.ssl.SslSelectChannelConnector">
+ <Set name="Port"><Property name="jetty.port.ssl" default="8443" /></Set>
+ <Set name="maxIdleTime">30000</Set>
+ <Set name="Acceptors">2</Set>
+ <Set name="AcceptQueueSize">100</Set>
+ <Set name="Keystore"><Property name="jetty.home" default="." />/etc/keystore</Set>
+ <Set name="Password">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
+ <Set name="KeyPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set>
+ <Set name="truststore"><Property name="jetty.home" default="." />/etc/keystore</Set>
+ <Set name="trustPassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
+ </New>
+ </Arg>
+ </Call>
+ -->
+
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+ <!-- To add a HTTP blocking connector -->
+ <!-- mixin jetty-bio.xml: -->
+ <!-- java -jar start.jar etc/jetty.xml etc/jetty-bio.xml -->
+ <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
+</Configure>
42 config/logback.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<configuration>
+
+ <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+ <file>/var/log/elasticinbox/elasticinbox.log</file>
+ <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
+ <fileNamePattern>/var/log/elasticinbox/elasticinbox.%i.log</fileNamePattern>
+ <minIndex>1</minIndex>
+ <maxIndex>5</maxIndex>
+ </rollingPolicy>
+ <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
+ <maxFileSize>10MB</maxFileSize>
+ </triggeringPolicy>
+ <encoder>
+ <pattern>%d{ISO8601} %-5level [%thread] %C{1} [%M:%L] - %msg%n</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%d{ISO8601} %-5level [%thread] %C{1} [%M:%L] - %msg%n</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="DEVNULL" class="ch.qos.logback.core.FileAppender">
+ <file>/dev/null</file>
+ <append>true</append>
+ <encoder>
+ <pattern>%msg%n</pattern>
+ </encoder>
+ </appender>
+
+ <!-- Disable Speed4j Stats in logfile -->
+ <logger name="com.elasticinbox.speed4j" level="INFO" additivity="false">
+ <appender-ref ref="DEVNULL" />
+ </logger>
+
+ <root level="INFO">
+ <appender-ref ref="FILE" />
+ </root>
+
+</configuration>
0 itests/.gitignore
No changes.
318 itests/pom.xml
@@ -0,0 +1,318 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <parent>
+ <relativePath>../poms/compiled/</relativePath>
+ <groupId>com.elasticinbox.parent.build</groupId>
+ <artifactId>compiled-bundle-settings</artifactId>
+ <version>0.2.0-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.elasticinbox</groupId>
+ <artifactId>elasticinbox-itests</artifactId>
+
+ <name>ElasticInbox Integration Tests</name>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.3.2</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+
+ <!-- pax exam Maven plugin
+ see: http://ops4j1.jira.com/wiki/display/paxexam/Configuration+using+Maven+Plugin
+ -->
+ <plugin>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>maven-paxexam-plugin</artifactId>
+ <version>1.2.4</version>
+ <executions>
+ <execution>
+ <id>generate-config</id>
+ <goals>
+ <goal>generate-depends-file</goal>
+ <goal>generate-config</goal>
+ </goals>
+ </execution>
+ </executions>
+ <!--
+ Maven based PAX Exam configuration
+ <configuration>
+ <options>
+ <workingDirectory>${project.build.directory}/paxexam</workingDirectory>
+ <platform>${target-framework}</platform>
+ <profiles>compendium,war,log,url</profiles>
+ </options>
+ <settings>
+ <dependency_options>org.ops4j.pax.web:pax-web-service@7</dependency_options>
+ </settings>
+ </configuration>
+ -->
+ </plugin>
+
+ </plugins>
+ </build>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>com.elasticinbox</groupId>
+ <artifactId>elasticinbox-common</artifactId>
+ <version>${project.version}</version>
+ <type>bundle</type>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.elasticinbox</groupId>
+ <artifactId>elasticinbox-config</artifactId>
+ <version>${project.version}</version>
+ <type>bundle</type>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.elasticinbox</groupId>
+ <artifactId>elasticinbox-core</artifactId>
+ <version>${project.version}</version>
+ <type>bundle</type>
+ <scope>provided</scope>
+ </dependency>
+ <!--
+ <dependency>
+ <groupId>com.elasticinbox</groupId>
+ <artifactId>elasticinbox-rest</artifactId>
+ <version>${project.version}</version>
+ <type>bundle</type>
+ <scope>provided</scope>
+ </dependency>
+ -->
+
+ <dependency>
+ <groupId>com.jayway.restassured</groupId>
+ <artifactId>rest-assured</artifactId>
+ <version>1.3</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.8.1</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- Jersey -->
+ <dependency>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>jersey-server</artifactId>
+ <version>${bundle.jersey.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.sun.jersey</groupId>
+ <artifactId>jersey-core</artifactId>
+ <version>${bundle.jersey.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.googlecode.guava-osgi</groupId>
+ <artifactId>guava-osgi</artifactId>
+ <version>${bundle.guava.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.ning</groupId>
+ <artifactId>compress-lzf</artifactId>
+ <version>${bundle.compress-lzf.version}</version>
+ <type>bundle</type>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ <version>${bundle.jackson.version}</version>
+ <type>bundle</type>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-core-asl</artifactId>
+ <version>${bundle.jackson.version}</version>
+ <type>bundle</type>
+ <scope>provided</scope>
+ </dependency>
+ <!--
+ <dependency>
+ <groupId>org.apache.james</groupId>
+ <artifactId>apache-mime4j-dom</artifactId>
+ <version>${bundle.mime4j.version}</version>
+ <type>bundle</type>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.james</groupId>
+ <artifactId>apache-mime4j-core</artifactId>
+ <version>${bundle.mime4j.version}</version>
+ <type>bundle</type>
+ <scope>provided</scope>
+ </dependency>
+ -->
+ <dependency>
+ <groupId>javax.mail</groupId>
+ <artifactId>mail</artifactId>
+ <version>${bundle.javamail.version}</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- Jclouds Dependencies -->
+ <dependency>
+ <groupId>org.jclouds</groupId>
+ <artifactId>jclouds-core</artifactId>
+ <version>${bundle.jclouds.version}</version>
+ <type>bundle</type>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jclouds</groupId>
+ <artifactId>jclouds-blobstore</artifactId>
+ <version>${bundle.jclouds.version}</version>
+ <type>bundle</type>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jclouds.api</groupId>
+ <artifactId>filesystem</artifactId>
+ <version>${bundle.jclouds.version}</version>
+ <type>bundle</type>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jclouds.api</groupId>
+ <artifactId>swift</artifactId>
+ <version>${bundle.jclouds.version}</version>
+ <type>bundle</type>
+ <scope>provided</scope>
+ </dependency>
+ <!-- AWS S3
+ <dependency>
+ <groupId>org.jclouds.api</groupId>
+ <artifactId>s3</artifactId>
+ <version>${bundle.jclouds.version}</version>
+ <type>bundle</type>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jclouds.common</groupId>
+ <artifactId>aws-common</artifactId>
+ <version>${bundle.jclouds.version}</version>
+ <type>bundle</type>
+ <scope>provided</scope>
+ </dependency>
+ -->
+ <dependency>
+ <groupId>org.jclouds.common</groupId>
+ <artifactId>openstack-common</artifactId>
+ <version>${bundle.jclouds.version}</version>
+ <type>bundle</type>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.aopalliance</artifactId>
+ <version>${bundle.aopalliance.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.commons-io</artifactId>
+ <version>${bundle.commons-io.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.javax-inject</artifactId>
+ <version>${bundle.javax-inject.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.oauth-commons</artifactId>
+ <version>${bundle.net.oauth.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.java-xmlbuilder</artifactId>
+ <version>${bundle.java-xmlbuilder.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicemix.bundles</groupId>
+ <artifactId>org.apache.servicemix.bundles.commons-lang</artifactId>
+ <version>${bundle.commons-lang.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.inject</groupId>
+ <artifactId>guice</artifactId>
+ <version>${bundle.guice.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.inject.extensions</groupId>
+ <artifactId>guice-assistedinject</artifactId>
+ <version>${bundle.guice.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ <version>${bundle.gson.version}</version>
+ </dependency>
+
+ <!-- Pax Exam Dependencies -->
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-junit4</artifactId>
+ <version>${bundle.paxexam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-container-paxrunner</artifactId>
+ <version>${bundle.paxexam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-link-assembly</artifactId>
+ <version>${bundle.paxexam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.exam</groupId>
+ <artifactId>pax-exam-testforge</artifactId>
+ <version>${bundle.paxexam.version}</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.ops4j.pax.runner</groupId>
+ <artifactId>pax-runner-no-jcl</artifactId>
+ <version>1.7.4</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
892 itests/src/test/java/com/elasticinbox/itests/RestIT.java
@@ -0,0 +1,892 @@
+/**
+ * Copyright (c) 2011 Optimax Software Ltd
+ *
+ * This file is part of ElasticInbox.
+ *
+ * ElasticInbox is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * ElasticInbox 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 General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * ElasticInbox. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.elasticinbox.itests;
+
+import static org.ops4j.pax.exam.CoreOptions.*;
+import static org.ops4j.pax.exam.OptionUtils.combine;
+import static org.ops4j.pax.exam.spi.container.PaxExamRuntime.createTestSystem;
+import static org.ops4j.pax.exam.spi.container.PaxExamRuntime.createContainer;
+
+import static org.hamcrest.Matchers.*;
+import static com.jayway.restassured.RestAssured.*;
+import static com.jayway.restassured.path.json.JsonPath.*;
+
+import groovyx.net.http.ContentType;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite.SuiteClasses;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.TimeoutException;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.junit.ExamReactorStrategy;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.ops4j.pax.exam.spi.reactors.EagerSingleStagedReactorFactory;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.elasticinbox.core.model.LabelCounters;
+import com.elasticinbox.core.model.Marker;
+import com.elasticinbox.core.model.ReservedLabels;
+import com.google.common.io.ByteStreams;
+import com.jayway.restassured.response.Response;
+
+/**
+ * Integration test for REST APIs
+ *
+ * @author Rustam Aliyev
+ */
+@RunWith(JUnit4TestRunner.class)
+@SuiteClasses({ RestIT.class })
+@ExamReactorStrategy(EagerSingleStagedReactorFactory.class)
+public class RestIT
+{
+ private static final String REST_PATH = "/rest/v1/test@elasticinbox.com";
+ private static final String EMAIL_LARGE_ATT = "/01-attach-utf8.eml";
+ private static final String EMAIL_REGULAR = "/01-headers-utf8.eml";
+
+ private final static Logger logger =
+ LoggerFactory.getLogger(RestIT.class);
+
+ @Configuration()
+ public Option[] config()
+ {
+ return options(
+ //junitBundles(),
+ felix(),
+ workingDirectory("target/paxrunner/"),
+ waitForFrameworkStartup(),
+ repository("https://repository.apache.org/snapshots/").allowSnapshots(),
+
+ // Configs
+ systemProperty("elasticinbox.config").value("../test-classes/elasticinbox.yaml"),
+ systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"),
+
+ // PAX Exam Bundles
+ mavenBundle().groupId("org.mortbay.jetty").artifactId("servlet-api").version("2.5-20110124"),
+ mavenBundle().groupId("org.ops4j.pax.web").artifactId("pax-web-api"),
+ mavenBundle().groupId("org.ops4j.pax.web").artifactId("pax-web-spi"),
+ mavenBundle().groupId("org.ops4j.pax.web").artifactId("pax-web-jetty-bundle"),
+ mavenBundle().groupId("org.ops4j.pax.web").artifactId("pax-web-extender-war"),
+
+ // REST-Assured Bundles
+ wrappedBundle(mavenBundle().groupId("com.jayway.restassured").artifactId("rest-assured").versionAsInProject()),
+ wrappedBundle(mavenBundle().groupId("org.codehaus.groovy.modules.http-builder").artifactId("http-builder").version("0.5.1")),
+ wrappedBundle(mavenBundle().groupId("org.hamcrest").artifactId("hamcrest-all").version("1.1")),
+ wrappedBundle(mavenBundle().groupId("xml-resolver").artifactId("xml-resolver").version("1.2")),
+ wrappedBundle(mavenBundle().groupId("net.sf.ezmorph").artifactId("ezmorph").version("1.0.6")),
+ wrappedBundle(mavenBundle().groupId("net.sf.json-lib").artifactId("json-lib").version("2.4").classifier("jdk15")),
+ wrappedBundle(mavenBundle().groupId("net.sourceforge.nekohtml").artifactId("nekohtml").version("1.9.15")),
+ wrappedBundle(mavenBundle().groupId("xerces").artifactId("xercesImpl").version("2.9.1")),
+ mavenBundle().groupId("org.codehaus.groovy").artifactId("groovy-all").version("1.7.10"),
+ //mavenBundle().groupId("commons-lang").artifactId("commons-lang").version("2.6"),
+ mavenBundle().groupId("commons-beanutils").artifactId("commons-beanutils").version("1.8.3"),
+ mavenBundle().groupId("commons-collections").artifactId("commons-collections").version("3.2.1"),
+ mavenBundle().groupId("org.apache.httpcomponents").artifactId("httpcore-osgi").version("4.1.1"),
+ mavenBundle().groupId("org.apache.httpcomponents").artifactId("httpclient-osgi").version("4.1.1"),
+
+ // jClouds and dependencies
+ mavenBundle().groupId("com.google.inject").artifactId("guice").versionAsInProject(),
+ mavenBundle().groupId("org.jclouds").artifactId("jclouds-core").versionAsInProject(),
+ mavenBundle().groupId("org.jclouds").artifactId("jclouds-blobstore").versionAsInProject(),
+ mavenBundle().groupId("org.jclouds.api").artifactId("filesystem").versionAsInProject(),
+ mavenBundle().groupId("org.jclouds.api").artifactId("swift").versionAsInProject(),
+ mavenBundle().groupId("org.jclouds.common").artifactId("openstack-common").versionAsInProject(),
+ //mavenBundle().groupId("org.jclouds.api").artifactId("s3").versionAsInProject(),
+ //mavenBundle().groupId("org.jclouds.common").artifactId("aws-common").versionAsInProject(),
+ mavenBundle().groupId("org.apache.servicemix.bundles").artifactId("org.apache.servicemix.bundles.aopalliance").versionAsInProject(),
+ mavenBundle().groupId("org.apache.servicemix.bundles").artifactId("org.apache.servicemix.bundles.commons-io").versionAsInProject(),
+ mavenBundle().groupId("org.apache.servicemix.bundles").artifactId("org.apache.servicemix.bundles.commons-lang").versionAsInProject(),
+ mavenBundle().groupId("org.apache.servicemix.bundles").artifactId("org.apache.servicemix.bundles.javax-inject").versionAsInProject(),
+ mavenBundle().groupId("org.apache.servicemix.bundles").artifactId("org.apache.servicemix.bundles.oauth-commons").versionAsInProject(),
+ mavenBundle().groupId("org.apache.servicemix.bundles").artifactId("org.apache.servicemix.bundles.java-xmlbuilder").versionAsInProject(),
+ mavenBundle().groupId("com.google.inject.extensions").artifactId("guice-assistedinject").versionAsInProject(),
+ mavenBundle().groupId("com.google.code.gson").artifactId("gson").versionAsInProject(),
+
+ // ElasticInbox Bundles
+ mavenBundle().groupId("com.googlecode.guava-osgi").artifactId("guava-osgi").versionAsInProject(),
+ mavenBundle().groupId("org.codehaus.jackson").artifactId("jackson-core-asl").versionAsInProject(),
+ mavenBundle().groupId("org.codehaus.jackson").artifactId("jackson-mapper-asl").versionAsInProject(),
+ mavenBundle().groupId("com.ning").artifactId("compress-lzf").versionAsInProject(),
+ mavenBundle().groupId("com.sun.jersey").artifactId("jersey-core").versionAsInProject(),
+ mavenBundle().groupId("com.sun.jersey").artifactId("jersey-server").versionAsInProject(),
+ mavenBundle().groupId("javax.mail").artifactId("mail").versionAsInProject(),
+ scanDir("../bundles/com.ecyrd.speed4j/target/"),
+ scanDir("../modules/common/target/"),
+ scanDir("../modules/config/target/"),
+ scanDir("../modules/core/target/"),
+ scanDir("../modules/rest/target/")
+ );
+ }
+
+ public static void main(String[] args) throws TimeoutException, IOException
+ {
+ createContainer(
+ createTestSystem(
+ combine(new RestIT().config(), profile("gogo")))).start();
+ }
+
+ @BeforeClass
+ public static void createAccountTest() {
+ // create account
+ expect().statusCode(201).when().post(REST_PATH);
+ }
+
+ @AfterClass
+ public static void deleteAccountTest() {
+ // delete account
+ expect().statusCode(204).when().delete(REST_PATH);
+ }
+
+ //@Test
+ public void bundleContextTest(BundleContext ctx)
+ {
+ //assertThat(ctx, is(notNullValue()));
+ logger.info("BundleContext of bundle injected: {}", ctx.getBundle().getSymbolicName());
+
+ for (Bundle b : ctx.getBundles()) {
+ logger.info("Bundle {} [state={}]", b.getSymbolicName(), b.getState());
+ }
+ }
+
+ @Test
+ public void reservedLabelsTest()
+ {
+ // check reserved labels
+ expect().
+ statusCode(200).and().
+ body("\"" + ReservedLabels.ALL_MAILS.getLabelId() + "\"", equalTo(ReservedLabels.ALL_MAILS.getLabelName())).
+ body("\"" + ReservedLabels.INBOX.getLabelId() + "\"", equalTo(ReservedLabels.INBOX.getLabelName())).
+ body("\"" + ReservedLabels.DRAFTS.getLabelId() + "\"", equalTo(ReservedLabels.DRAFTS.getLabelName())).
+ body("\"" + ReservedLabels.SENT.getLabelId() + "\"", equalTo(ReservedLabels.SENT.getLabelName())).
+ body("\"" + ReservedLabels.TRASH.getLabelId() + "\"", equalTo(ReservedLabels.TRASH.getLabelName())).
+ body("\"" + ReservedLabels.SPAM.getLabelId() + "\"", equalTo(ReservedLabels.SPAM.getLabelName())).
+ body("\"" + ReservedLabels.STARRED.getLabelId() + "\"", equalTo(ReservedLabels.STARRED.getLabelName())).
+ body("\"" + ReservedLabels.IMPORTANT.getLabelId() + "\"", equalTo(ReservedLabels.IMPORTANT.getLabelName())).
+ body("\"" + ReservedLabels.NOTIFICATIONS.getLabelId() + "\"",equalTo(ReservedLabels.NOTIFICATIONS.getLabelName())).
+ body("\"" + ReservedLabels.ATTACHMENTS.getLabelId() + "\"", equalTo(ReservedLabels.ATTACHMENTS.getLabelName())).
+ when().
+ get(REST_PATH + "/mailbox");
+ }
+
+ @Test
+ public void reservedLabelsWithMetadataTest()
+ {
+ // check labels metadata
+ expect().
+ statusCode(200).and().
+ body("\"" + ReservedLabels.INBOX.getLabelId() + "\".name", equalTo(ReservedLabels.INBOX.getLabelName())).
+ body("\"" + ReservedLabels.INBOX.getLabelId() + "\".size", greaterThanOrEqualTo(0)).
+ body("\"" + ReservedLabels.INBOX.getLabelId() + "\".new", greaterThanOrEqualTo(0)).
+ body("\"" + ReservedLabels.INBOX.getLabelId() + "\".total", greaterThanOrEqualTo(0)).
+ when().
+ get(REST_PATH + "/mailbox?metadata=true");
+ }
+
+ @Test
+ public void labelListAddDeleteTest()
+ {
+ String labelName = "MyLabel";
+ String labelRename = "MyAnotherLabel";
+ Integer labelId = null;
+
+ // add label
+ labelId = addLabel(labelName);
+
+ // check added label
+ expect().
+ statusCode(200).and().
+ body("\"" + labelId + "\"", equalTo(labelName)).
+ when().
+ get(REST_PATH + "/mailbox");
+
+ logger.info("Add label test OK");
+
+ // rename label
+ given().
+ pathParam("labelId", labelId).
+ expect().
+ statusCode(204).
+ when().
+ put(REST_PATH + "/mailbox/label/{labelId}?name=" + labelRename);
+
+ // check renamed label
+ expect().
+ statusCode(200).and().
+ body("\"" + labelId + "\"", equalTo(labelRename)).
+ when().
+ get(REST_PATH + "/mailbox");
+
+ logger.info("Rename label test OK");
+
+ // adding existing label, should fail
+ given().
+ pathParam("labelName", labelRename).
+ expect().
+ statusCode(400).
+ when().
+ post(REST_PATH + "/mailbox/label?name={labelName}");
+
+ // adding label under existing label hierarchically, should fail
+// given().
+// pathParam("labelName", labelRename + "/subLabel").
+// expect().
+// statusCode(400).
+// when().
+// post(REST_PATH + "/mailbox/label?name={labelName}");
+
+ // delete label
+ given().
+ pathParam("labelId", labelId).
+ expect().
+ statusCode(204).
+ when().
+ delete(REST_PATH + "/mailbox/label/{labelId}");
+
+ // check deleted label
+ expect().
+ statusCode(200).and().
+ body("\"" + labelId + "\"", is(nullValue())).
+ when().
+ get(REST_PATH + "/mailbox").asString();
+
+ logger.info("Delete label test OK");
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void messageAddListViewDeletePurgeTest() throws IOException
+ {
+ long fileSizeA = getResourceSize(EMAIL_REGULAR);
+
+ String messageId = null;
+ Map<String, UUID> messages = new HashMap<String, UUID>(2);
+ Integer labelId = ReservedLabels.INBOX.getLabelId();
+
+ // add message
+ messages.put("headers", addMessage(EMAIL_REGULAR, labelId));
+ messages.put("attach", addMessage(EMAIL_LARGE_ATT, labelId));
+
+ logger.info("Message Store Test OK");
+
+ // check message listing
+ given().
+ pathParam("labelId", labelId).
+ expect().
+ statusCode(200).and().
+ body("", hasItems(messages.get("headers").toString(), messages.get("attach").toString())).
+ when().
+ get(REST_PATH + "/mailbox/label/{labelId}");
+
+ logger.info("Message List Test OK");
+
+ // TODO: need to implement sequence order to test reverese
+ // check reverse message listing (only oldest message should be listed)
+// given().
+// pathParam("labelId", labelId).
+// expect().
+// statusCode(200).and().
+// body("", not( hasItems(messages.get("headers").toString()) )).
+// body("", not( hasItems(messages.get("attach").toString()) )).
+// when().
+// get(REST_PATH + "/mailbox/label/{labelId}?reverse=false&count=1");
+//
+// logger.info("Message Reverse List Test OK");
+
+ // check message list with metadata
+ messageId = messages.get("headers").toString();
+ given().
+ pathParam("labelId", labelId).
+ pathParam("messageId", messageId).
+ expect().
+ statusCode(200).and().
+ body(messageId + ".labels", hasItems(0, 1)).
+ body(messageId + ".size", equalTo((int) fileSizeA)).
+ body(messageId + ".from.address", hasItems(containsString("@"))).
+ body(messageId + ".to.address", hasItems(containsString("@"))).
+ body(messageId + ".subject", is(notNullValue())).
+ when().
+ get(REST_PATH + "/mailbox/label/{labelId}?metadata=true&count=2&start={messageId}");
+
+ logger.info("Message List with Metadata Test OK");
+
+ // check parsed message
+ messageId = messages.get("headers").toString();
+ given().
+ pathParam("labelId", labelId).
+ pathParam("messageId", messageId).
+ expect().
+ statusCode(200).and().
+ body("message.labels", hasItems(0, 1)).
+ body("message.size", equalTo((int) fileSizeA)).
+ body("message.from.address", hasItems(containsString("@"))).
+ body("message.to.address", hasItems(containsString("@"))).
+ body("message.subject", is(notNullValue())).
+ body("message.htmlBody", is(notNullValue())).
+ body("message.textBody", is(nullValue())).
+ when().
+ get(REST_PATH + "/mailbox/message/{messageId}?adjacent=true&label={labelId}");
+
+ logger.info("Parsed Message Fetch Test OK");
+
+ // delete message (from all labels)
+ given().
+ pathParam("messageId", messageId).
+ expect().
+ statusCode(204).
+ when().
+ delete(REST_PATH + "/mailbox/message/{messageId}");
+
+ // check deleted message in labels
+ given().
+ pathParam("labelId", labelId).
+ expect().
+ statusCode(200).and().
+ body(messageId, is(nullValue())).
+ when().
+ get(REST_PATH + "/mailbox/label/{labelId}?metadata=true");
+
+ // message should remain until purged
+ given().
+ pathParam("messageId", messageId).
+ expect().
+ statusCode(200).and().
+ body("message.labels", hasItems(0, 1)).
+ when().
+ get(REST_PATH + "/mailbox/message/{messageId}");
+
+ logger.info("Delete Message Test OK");
+
+ // purge deleted messages
+ given().
+ pathParam("ageDate", new SimpleDateFormat("yyyy/MM/dd").format(new Date()) + " 23:59").
+ expect().
+ statusCode(204).
+ when().
+ put(REST_PATH + "/mailbox/purge?age={ageDate}");
+
+ // check purged message
+ given().
+ pathParam("messageId", messageId).
+ expect().
+ statusCode(400).
+ when().
+ get(REST_PATH + "/mailbox/message/{messageId}");
+
+ logger.info("Purge Message Test OK");
+ }
+
+ @Test
+ public void messageAddRemoveLabelsMarkersTest() throws IOException
+ {
+ // add labels
+ Integer labelId1 = addLabel("CustomLabelTest3739");
+ Integer labelId2 = addLabel("CustomLabelTest2398");
+
+ // add message
+ UUID messageId = addMessage(EMAIL_REGULAR, ReservedLabels.INBOX.getLabelId());
+
+ // assign labels and marker to the message
+ given().
+ pathParam("messageId", messageId).
+ pathParam("labelId1", labelId1).
+ pathParam("labelId2", labelId2).
+ pathParam("seenMarker", Marker.SEEN.toString().toLowerCase()).
+ expect().
+ statusCode(204).
+ when().
+ put(REST_PATH + "/mailbox/message/{messageId}?addlabel={labelId1}&addlabel={labelId2}&addmarker={seenMarker}");
+
+ // verify labels and marker
+ given().
+ pathParam("messageId", messageId).
+ expect().
+ statusCode(200).and().
+ body("message.labels", hasItems(0, 1, labelId1, labelId2)).
+ body("message.markers", hasItems(Marker.SEEN.toString().toUpperCase())).
+ when().
+ get(REST_PATH + "/mailbox/message/{messageId}");
+
+ // assign/remove labels and markers to the message
+ given().
+ pathParam("messageId", messageId).
+ pathParam("removeLabel", labelId1).
+ pathParam("addLabel", ReservedLabels.SPAM.getLabelId()).
+ pathParam("removeMarker", Marker.SEEN.toString().toLowerCase()).
+ pathParam("addMarker", Marker.REPLIED.toString().toLowerCase()).
+ expect().
+ statusCode(204).
+ when().
+ put(REST_PATH + "/mailbox/message/{messageId}?addlabel={addLabel}&removelabel={removeLabel}&removemarker={removeMarker}&addmarker={addMarker}");
+
+ // verify labels and markers
+ given().
+ pathParam("messageId", messageId).
+ expect().
+ statusCode(200).and().
+ body("message.labels", hasItems(0, 1, labelId2, ReservedLabels.SPAM.getLabelId())).
+ body("message.labels", not( hasItems(labelId1) )).
+ body("message.markers", hasItems(Marker.REPLIED.toString().toUpperCase())).
+ body("message.markers", not( hasItems(Marker.SEEN.toString().toUpperCase()) )).
+ when().
+ get(REST_PATH + "/mailbox/message/{messageId}");
+ }
+
+ @Test
+ public void messageBatchMofifyDeleteTest() throws IOException
+ {
+ // add labels
+ Integer labelId1 = addLabel("BatchLabelTest0912");
+ Integer labelId2 = addLabel("BatchLabelTest1290");
+
+ // add messages
+ UUID messageId1 = addMessage(EMAIL_REGULAR, ReservedLabels.INBOX.getLabelId());
+ UUID messageId2 = addMessage(EMAIL_LARGE_ATT, ReservedLabels.INBOX.getLabelId());
+
+ // batch add labels and markers
+ given().
+ pathParam("labelId1", labelId1).
+ pathParam("labelId2", labelId2).
+ pathParam("seenMarker", Marker.SEEN.toString().toLowerCase()).
+ request().body("[\"" + messageId1.toString() + "\", \"" + messageId2.toString() + "\"]").contentType(ContentType.JSON).
+ expect().
+ statusCode(204).
+ when().
+ put(REST_PATH + "/mailbox/message?addlabel={labelId1}&addlabel={labelId2}&addmarker={seenMarker}");
+
+ // verify labels and markers
+ given().
+ pathParam("labelId", ReservedLabels.ALL_MAILS.getLabelId()).
+ expect().
+ statusCode(200).and().
+ body(messageId1.toString() + ".labels", hasItems(0, 1, labelId1, labelId2)).
+ body(messageId2.toString() + ".labels", hasItems(0, 1, labelId1, labelId2)).
+ body(messageId1.toString() + ".markers", hasItems(Marker.SEEN.toString().toUpperCase())).
+ body(messageId2.toString() + ".markers", hasItems(Marker.SEEN.toString().toUpperCase())).
+ when().
+ get(REST_PATH + "/mailbox/label/{labelId}?metadata=true");
+
+ /**
+ * Batch delete test is skipped at the moment. HTTP DELETE request body
+ * is not supported by RestAssured/HTTPBuilder at the moment. See:
+ *
+ * http://code.google.com/p/rest-assured/issues/detail?id=48
+ * http://stackoverflow.com/questions/299628/is-an-entity-body-allowed-for-an-http-delete-request
+ *
+ */
+
+ // batch delete messages
+// given().
+// request().body("[\"" + messageId1.toString() + "\", \"" + messageId2.toString() + "\"]").contentType(ContentType.JSON).
+// expect().
+// statusCode(204).
+// when().
+// delete(REST_PATH + "/mailbox/message");
+
+ // verify batch delete
+// given().
+// pathParam("labelId", ReservedLabels.ALL_MAILS.getLabelId()).
+// expect().
+// statusCode(200).and().
+// body(messageId1.toString(), is(nullValue())).
+// body(messageId2.toString(), is(nullValue())).
+// when().
+// get(REST_PATH + "/mailbox/label/{labelId}?metadata=true");
+ }
+
+ @Test
+ public void messageAttachmentAndRawTest() throws IOException
+ {
+ // add message
+ UUID messageId = addMessage(EMAIL_LARGE_ATT, ReservedLabels.INBOX.getLabelId());
+ long fileSize = getResourceSize(EMAIL_LARGE_ATT);
+
+ // get attachment by part id
+ given().
+ pathParam("messageId", messageId).
+ pathParam("partId", 3).
+ expect().
+ statusCode(200).and().
+ header("Content-Type", equalTo("application/pdf")).
+ //header("Content-Length", equalTo("64736")).
+ header("Content-Disposition", containsString("attachment; filename=")).
+ when().
+ get(REST_PATH + "/mailbox/message/{messageId}/{partId}");
+
+ // get attachment by content id
+ given().
+ pathParam("messageId", messageId).
+ pathParam("contentId", "<image-001>").
+ expect().
+ statusCode(200).and().
+ header("Content-Type", equalTo("image/png")).
+ //header("Content-Length", equalTo("27136")).
+ header("Content-Disposition", containsString("attachment; filename=")).
+ when().
+ get(REST_PATH + "/mailbox/message/{messageId}/{contentId}");
+
+ // get raw message source
+ given().
+ pathParam("messageId", messageId).
+ expect().
+ statusCode(200).and().
+ header("Content-Type", equalTo("text/plain")).
+ header("Content-Length", equalTo(String.valueOf(fileSize))).
+ when().
+ get(REST_PATH + "/mailbox/message/{messageId}/raw");
+ }
+
+ @Test
+ public void messageUpdateTest() throws IOException
+ {
+ // add message
+ UUID messageId = addMessage(EMAIL_LARGE_ATT, ReservedLabels.INBOX.getLabelId());
+
+ // add labels and markers
+ given().
+ pathParam("messageId", messageId).
+ pathParam("labelId1", ReservedLabels.IMPORTANT.getLabelId()).
+ pathParam("labelId2", ReservedLabels.STARRED.getLabelId()).
+ pathParam("marker1", Marker.SEEN.toString().toLowerCase()).
+ expect().
+ statusCode(204).
+ when().
+ put(REST_PATH + "/mailbox/message/{messageId}?addlabel={labelId1}&addlabel={labelId2}&addmarker={marker1}");
+
+ // overwrite message
+ InputStream fin = this.getClass().getResourceAsStream(EMAIL_REGULAR);
+ byte[] messageBytes = ByteStreams.toByteArray(fin);
+ fin.close();
+
+ Response response =
+ given().
+ pathParam("messageId", messageId.toString()).
+ request().body(messageBytes).contentType(ContentType.BINARY).
+ expect().
+ statusCode(201).
+ when().
+ post(REST_PATH + "/mailbox/message/{messageId}");
+
+ UUID newMessageId = UUID.fromString( with(response.asString()).getString("id") );
+
+ // verify that message updated and labels/markers preserved
+ given().
+ pathParam("messageId", newMessageId.toString()).
+ expect().
+ statusCode(200).and().
+ body("message.labels", hasItems(ReservedLabels.IMPORTANT.getLabelId(), ReservedLabels.STARRED.getLabelId())).
+ body("message.markers", hasItems(Marker.SEEN.toString().toUpperCase())).
+ when().
+ get(REST_PATH + "/mailbox/message/{messageId}");
+
+ }
+
+ @Test
+ public void countersTest() throws IOException
+ {
+ LabelCounters allCounters = new LabelCounters();
+ LabelCounters inboxCounters = new LabelCounters();
+ LabelCounters spamCounters = new LabelCounters();
+
+ // check label counter before message added
+ Response response = expect().statusCode(200).when().get(REST_PATH + "/mailbox?metadata=true");
+ allCounters = getCounters(response, ReservedLabels.ALL_MAILS.getLabelId());
+ inboxCounters = getCounters(response, ReservedLabels.INBOX.getLabelId());
+ spamCounters = getCounters(response, ReservedLabels.SPAM.getLabelId());
+
+ // add message A
+ long fileSizeA = getResourceSize(EMAIL_REGULAR);
+ UUID messageIdA = addMessage(EMAIL_REGULAR, ReservedLabels.INBOX.getLabelId());
+
+ // check label counters
+ response =
+ expect().
+ statusCode(200).and().
+ body("\"" + ReservedLabels.ALL_MAILS.getLabelId() + "\".size",
+ equalTo((int) (allCounters.getTotalBytes().longValue() + fileSizeA))).
+ body("\"" + ReservedLabels.ALL_MAILS.getLabelId() + "\".total",
+ equalTo((int) (allCounters.getTotalMessages().longValue() + 1))).
+ body("\"" + ReservedLabels.ALL_MAILS.getLabelId() + "\".new",
+ equalTo((int) (allCounters.getNewMessages().longValue() + 1))).
+ body("\"" + ReservedLabels.INBOX.getLabelId() + "\".size",
+ equalTo((int) (inboxCounters.getTotalBytes().longValue() + fileSizeA))).
+ body("\"" + ReservedLabels.INBOX.getLabelId() + "\".total",
+ equalTo((int) (inboxCounters.getTotalMessages().longValue() + 1))).
+ body("\"" + ReservedLabels.INBOX.getLabelId() + "\".new",
+ equalTo((int) (inboxCounters.getNewMessages().longValue() + 1))).
+ when().
+ get(REST_PATH + "/mailbox?metadata=true");
+
+ // add label SPAM to message A
+ given().
+ pathParam("messageId", messageIdA.toString()).
+ pathParam("labelId", ReservedLabels.SPAM.getLabelId()).
+ expect().
+ statusCode(204).
+ when().
+ put(REST_PATH + "/mailbox/message/{messageId}?addlabel={labelId}");
+
+ // check label counters
+ response =
+ expect().
+ statusCode(200).and().
+ body("\"" + ReservedLabels.SPAM.getLabelId() + "\".size",
+ equalTo((int) (spamCounters.getTotalBytes().longValue() + fileSizeA))).
+ body("\"" + ReservedLabels.SPAM.getLabelId() + "\".total",
+ equalTo((int) (spamCounters.getTotalMessages().longValue() + 1))).
+ body("\"" + ReservedLabels.SPAM.getLabelId() + "\".new",
+ equalTo((int) (spamCounters.getNewMessages().longValue() + 1))).
+ when().
+ get(REST_PATH + "/mailbox?metadata=true");
+
+ // update counters
+ allCounters = getCounters(response, ReservedLabels.ALL_MAILS.getLabelId());
+ inboxCounters = getCounters(response, ReservedLabels.INBOX.getLabelId());
+ spamCounters = getCounters(response, ReservedLabels.SPAM.getLabelId());
+
+ // mark message as read
+ given().
+ pathParam("messageId", messageIdA.toString()).
+ pathParam("marker", Marker.SEEN.toString().toLowerCase()).
+ expect().
+ statusCode(204).
+ when().
+ put(REST_PATH + "/mailbox/message/{messageId}?addmarker={marker}");
+
+ // check label counters
+ response =
+ expect().
+ statusCode(200).and().
+ body("\"" + ReservedLabels.ALL_MAILS.getLabelId() + "\".new",
+ equalTo((int) (allCounters.getNewMessages().longValue() - 1))).
+ body("\"" + ReservedLabels.INBOX.getLabelId() + "\".new",
+ equalTo((int) (inboxCounters.getNewMessages().longValue() - 1))).
+ body("\"" + ReservedLabels.SPAM.getLabelId() + "\".new",
+ equalTo((int) (spamCounters.getNewMessages().longValue() - 1))).
+ when().
+ get(REST_PATH + "/mailbox?metadata=true");
+
+ // update counters
+ allCounters = getCounters(response, ReservedLabels.ALL_MAILS.getLabelId());
+ inboxCounters = getCounters(response, ReservedLabels.INBOX.getLabelId());
+ spamCounters = getCounters(response, ReservedLabels.SPAM.getLabelId());
+
+ // remove label INBOX from message A
+ given().
+ pathParam("messageId", messageIdA.toString()).
+ pathParam("labelId", ReservedLabels.INBOX.getLabelId()).
+ expect().
+ statusCode(204).
+ when().
+ put(REST_PATH + "/mailbox/message/{messageId}?removelabel={labelId}");
+
+ // check label counters
+ response =
+ expect().
+ statusCode(200).and().
+ body("\"" + ReservedLabels.ALL_MAILS.getLabelId() + "\".size",
+ equalTo((int) (allCounters.getTotalBytes().longValue()))).
+ body("\"" + ReservedLabels.ALL_MAILS.getLabelId() + "\".total",
+ equalTo((int) (allCounters.getTotalMessages().longValue()))).
+ body("\"" + ReservedLabels.ALL_MAILS.getLabelId() + "\".new",
+ equalTo((int) (allCounters.getNewMessages().longValue()))).
+ body("\"" + ReservedLabels.INBOX.getLabelId() + "\".size",
+ equalTo((int) (inboxCounters.getTotalBytes().longValue() - fileSizeA))).
+ body("\"" + ReservedLabels.INBOX.getLabelId() + "\".total",
+ equalTo((int) (inboxCounters.getTotalMessages().longValue() - 1))).
+ body("\"" + ReservedLabels.INBOX.getLabelId() + "\".new",
+ equalTo((int) (inboxCounters.getNewMessages().longValue()))).
+ body("\"" + ReservedLabels.SPAM.getLabelId() + "\".size",
+ equalTo((int) (spamCounters.getTotalBytes().longValue()))).
+ body("\"" + ReservedLabels.SPAM.getLabelId() + "\".total",
+ equalTo((int) (spamCounters.getTotalMessages().longValue()))).
+ body("\"" + ReservedLabels.SPAM.getLabelId() + "\".new",
+ equalTo((int) (spamCounters.getNewMessages().longValue()))).
+ when().
+ get(REST_PATH + "/mailbox?metadata=true");
+
+ // update counters
+ allCounters = getCounters(response, ReservedLabels.ALL_MAILS.getLabelId());
+ inboxCounters = getCounters(response, ReservedLabels.INBOX.getLabelId());
+ spamCounters = getCounters(response, ReservedLabels.SPAM.getLabelId());
+
+ // add message B to SPAM
+ long fileSizeB = getResourceSize(EMAIL_LARGE_ATT);
+ UUID messageIdB = addMessage(EMAIL_LARGE_ATT, ReservedLabels.SPAM.getLabelId());
+
+ // check label counters
+ response =
+ expect().
+ statusCode(200).and().
+ body("\"" + ReservedLabels.ALL_MAILS.getLabelId() + "\".size",
+ equalTo((int) (allCounters.getTotalBytes().longValue() + fileSizeB))).
+ body("\"" + ReservedLabels.ALL_MAILS.getLabelId() + "\".total",
+ equalTo((int) (allCounters.getTotalMessages().longValue() + 1))).
+ body("\"" + ReservedLabels.ALL_MAILS.getLabelId() + "\".new",
+ equalTo((int) (allCounters.getNewMessages().longValue() + 1))).
+ body("\"" + ReservedLabels.INBOX.getLabelId() + "\".size",
+ equalTo((int) (inboxCounters.getTotalBytes().longValue()))).
+ body("\"" + ReservedLabels.INBOX.getLabelId() + "\".total",
+ equalTo((int) (inboxCounters.getTotalMessages().longValue()))).
+ body("\"" + ReservedLabels.INBOX.getLabelId() + "\".new",
+ equalTo((int) (inboxCounters.getNewMessages().longValue()))).
+ body("\"" + ReservedLabels.SPAM.getLabelId() + "\".size",
+ equalTo((int) (spamCounters.getTotalBytes().longValue() + fileSizeB))).
+ body("\"" + ReservedLabels.SPAM.getLabelId() + "\".total",
+ equalTo((int) (spamCounters.getTotalMessages().longValue() + 1))).
+ body("\"" + ReservedLabels.SPAM.getLabelId() + "\".new",
+ equalTo((int) (spamCounters.getNewMessages().longValue() + 1))).
+ when().
+ get(REST_PATH + "/mailbox?metadata=true");
+
+ // update counters
+ allCounters = getCounters(response, ReservedLabels.ALL_MAILS.getLabelId());
+ inboxCounters = getCounters(response, ReservedLabels.INBOX.getLabelId());
+ spamCounters = getCounters(response, ReservedLabels.SPAM.getLabelId());
+
+ // remove message A
+ given().
+ pathParam("messageId", messageIdA).
+ expect().
+ statusCode(204).
+ when().
+ delete(REST_PATH + "/mailbox/message/{messageId}");
+
+ // check label counters
+ response =
+ expect().
+ statusCode(200).and().
+ body("\"" + ReservedLabels.ALL_MAILS.getLabelId() + "\".size",
+ equalTo((int) (allCounters.getTotalBytes().longValue() - fileSizeA))).
+ body("\"" + ReservedLabels.ALL_MAILS.getLabelId() + "\".total",
+ equalTo((int) (allCounters.getTotalMessages().longValue() - 1))).
+ body("\"" + ReservedLabels.ALL_MAILS.getLabelId() + "\".new",
+ equalTo((int) (allCounters.getNewMessages().longValue()))).
+ body("\"" + ReservedLabels.SPAM.getLabelId() + "\".size",
+ equalTo((int) (spamCounters.getTotalBytes().longValue() - fileSizeA))).
+ body("\"" + ReservedLabels.SPAM.getLabelId() + "\".total",
+ equalTo((int) (spamCounters.getTotalMessages().longValue() - 1))).
+ body("\"" + ReservedLabels.SPAM.getLabelId() + "\".new",
+ equalTo((int) (spamCounters.getNewMessages().longValue()))).
+ when().
+ get(REST_PATH + "/mailbox?metadata=true");
+ }
+
+ /**
+ * Adds message throught REST API and returns new message UUID
+ *
+ * @param messageFile
+ * @param labelId
+ * @return
+ * @throws IOException