View Javadoc

1   /****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  
20  package org.apache.james.mpt.ant;
21  
22  import java.io.File;
23  import java.io.FileReader;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.Reader;
27  import java.io.StringReader;
28  import java.util.ArrayList;
29  import java.util.Collection;
30  import java.util.Iterator;
31  
32  import org.apache.james.mpt.ExternalHostSystem;
33  import org.apache.james.mpt.Monitor;
34  import org.apache.james.mpt.ProtocolSessionBuilder;
35  import org.apache.james.mpt.Runner;
36  import org.apache.james.mpt.ScriptedUserAdder;
37  import org.apache.tools.ant.BuildException;
38  import org.apache.tools.ant.Project;
39  import org.apache.tools.ant.Task;
40  import org.apache.tools.ant.types.Resource;
41  import org.apache.tools.ant.types.ResourceCollection;
42  import org.apache.tools.ant.types.resources.FileResource;
43  import org.apache.tools.ant.types.resources.Union;
44  
45  /**
46   * Task executes MPT scripts against a server
47   * running on a given port and host.
48   */
49  public class MailProtocolTestTask extends Task implements Monitor {
50  
51      private boolean quiet = false;
52      private File script;
53      private Union scripts;
54      private int port = 0;
55      private String host = "127.0.0.1";
56      private boolean skip = false;
57      private String shabang = null;
58      private Collection<AddUser> users = new ArrayList<AddUser>();
59      private String errorProperty;
60      
61      /**
62       * Gets the error property.
63       * 
64       * @return name of the ant property to be set on error,
65       * null if the script should terminate on error
66       */
67      public String getErrorProperty() {
68          return errorProperty;
69      }
70  
71      /**
72       * Sets the error property.
73       * @param errorProperty name of the ant property to be set on error,
74       * nul if the script should terminate on error
75       */
76      public void setErrorProperty(String errorProperty) {
77          this.errorProperty = errorProperty;
78      }
79  
80      /**
81       * Should progress output be suppressed?
82       * @return true if progress information should be suppressed,
83       * false otherwise
84       */
85      public boolean isQuiet() {
86          return quiet;
87      }
88  
89      /**
90       * Sets whether progress output should be suppressed/
91       * @param quiet true if progress information should be suppressed,
92       * false otherwise
93       */
94      public void setQuiet(boolean quiet) {
95          this.quiet = quiet;
96      }
97  
98      /**
99       * Should the execution be skipped?
100      * @return true if exection should be skipped, 
101      * otherwise false
102      */
103     public boolean isSkip() {
104         return skip;
105     }
106 
107     /**
108      * Sets execution skipping.
109      * @param skip true to skip excution
110      */
111     public void setSkip(boolean skip) {
112         this.skip = skip;
113     }
114 
115     /**
116      * Gets the host (either name or number) against which this
117      * test will run.
118      * @return host, not null
119      */
120     public String getHost() {
121         return host;
122     }
123 
124     /**
125      * Sets the host (either name or number) against which this
126      * test will run.
127      * @param host not null
128      */
129     public void setHost(String host) {
130         this.host = host;
131     }
132 
133     /**
134      * Gets the port against which this test will run.
135      * @return port number
136      */
137     public int getPort() {
138         return port;
139     }
140 
141     /**
142      * Sets the port aginst which this test will run.
143      * @param port port number
144      */
145     public void setPort(int port) {
146         this.port = port;
147     }
148 
149     /**
150      * Gets the script to execute.
151      * @return file containing test script
152      */
153     public File getScript() {
154         return script;
155     }
156 
157     /**
158      * Sets the script to execute.
159      * @param script not null
160      */
161     public void setScript(File script) {
162         this.script = script;
163     }
164 
165     /**
166      * Gets script shabang.
167      * This will be substituted for the first server response.
168      * @return script shabang, 
169      * or null for no shabang
170      */
171     public String getShabang() {
172         return shabang;
173     }
174     
175     /**
176      * Sets the script shabang.
177      * When not null, this value will be used to be substituted for the 
178      * first server response.
179      * @param shabang script shabang, 
180      * or null for no shabang.
181      */
182     public void setShabang(String shabang) {
183         this.shabang = shabang;
184     }
185 
186     @Override
187     public void execute() throws BuildException {
188         if (port <= 0) {
189             throw new BuildException("Port must be set to a positive integer");
190         }
191         
192         if (scripts == null && script == null) {
193             throw new BuildException("Scripts must be specified as an embedded resource collection"); 
194         }
195         
196         if (scripts != null && script != null) {
197             throw new BuildException("Scripts can be specified either by the script attribute or as resource collections but not both."); 
198         }
199         
200         for(final Iterator it=users.iterator();it.hasNext();) {
201             final AddUser user = (AddUser) it.next();
202             user.validate();
203         }
204         
205         if(skip) {
206             log("Skipping excution");
207         } else if (errorProperty == null) {
208             doExecute();
209         } else {
210             try {
211                 doExecute();
212             } catch (BuildException e) {
213                 final Project project = getProject();
214                 project.setProperty(errorProperty, e.getMessage());
215                 log(e, Project.MSG_DEBUG);
216             }
217         }
218     }
219 
220     public void add(ResourceCollection resources) {
221         if (scripts == null) {
222             scripts = new Union();
223         }
224         scripts.add(resources);
225     }
226     
227     private void doExecute() throws BuildException {
228         for (final Iterator it=users.iterator();it.hasNext();) {
229             final AddUser userAdder = (AddUser) it.next();
230             userAdder.execute();
231         }
232         
233         final ExternalHostSystem host = new ExternalHostSystem(getHost(), getPort(), this, getShabang(), null);
234         final ProtocolSessionBuilder builder = new ProtocolSessionBuilder();
235         
236         if (scripts == null) {
237             scripts = new Union();
238             scripts.add(new FileResource(script));
239         }
240         
241         for (final Iterator it=scripts.iterator();it.hasNext();) {
242             final Resource resource = (Resource) it.next();
243             try {
244                 final Runner runner = new Runner();
245                 
246                 try {
247                     
248                     final InputStream inputStream = resource.getInputStream();
249                     final String name = resource.getName();
250                     builder.addProtocolLines(name == null ? "[Unknown]" : name, inputStream, runner.getTestElements());
251                     runner.runSessions(host);
252                     
253                 } catch (UnsupportedOperationException e) {
254                     log("Resource cannot be read: " + resource.getName(), Project.MSG_WARN);
255                 }
256             } catch (IOException e) {
257                 throw new BuildException("Cannot load script " + resource.getName(), e);
258             } catch (Exception e) {
259                 log(e.getMessage(), Project.MSG_ERR);
260                 throw new BuildException("[FAILURE] in script " + resource.getName() + "\n" + e.getMessage(), e);
261             }
262             
263         }
264     
265     }
266     
267     public AddUser createAddUser() {
268         final AddUser result = new AddUser();
269         users.add(result);
270         return result;
271     }
272 
273     /**
274      * Adds a user.
275      */
276     public class AddUser {
277         
278         private int port;
279         private String user;
280         private String passwd;
281         private File script;
282         private String scriptText;
283 
284         /**
285          * Gets the port against which the user addition
286          * script should be executed.
287          * @return port number
288          */
289         public int getPort() {
290             return port;
291         }
292 
293         /**
294          * Sets the port against which the user addition
295          * script should be executed.
296          * @param port port number
297          */
298         public void setPort(int port) {
299             this.port = port;
300         }
301 
302         /**
303          * Gets the password for the user.
304          * @return password not null
305          */
306         public String getPasswd() {
307             return passwd;
308         }
309 
310         /**
311          * Sets the password for the user.
312          * This will be passed in the user creation script.
313          * @param passwd not null
314          */
315         public void setPasswd(String passwd) {
316             this.passwd = passwd;
317         }
318 
319         /**
320          * Gets the name of the user to be created.
321          * @return user name, not null
322          */
323         public String getUser() {
324             return user;
325         }
326 
327         /**
328          * Sets the name of the user to be created.
329          * @param user not null
330          */
331         public void setUser(String user) {
332             this.user = user;
333         }
334         
335         /**
336          * Sets user addition script.
337          * @param scriptText not null
338          */
339         public void addText(String scriptText) {
340             this.scriptText = getProject().replaceProperties(scriptText);
341         }
342 
343         /**
344          * Gets the file containing the user creation script.
345          * @return not null
346          */
347         public File getScript() {
348             return script;
349         }
350 
351         /**
352          * Sets the file containing the user creation script.
353          * @param script not null
354          */
355         public void setScript(File script) {
356             this.script = script;
357         }
358         
359         /**
360          * Validates mandatory fields have been filled.
361          */
362         void validate() throws BuildException {
363             if (script == null && scriptText == null) {
364                 throw new BuildException("Either the 'script' attribute must be set, or the body must contain the text of the script");
365             }
366             
367             if (script != null && scriptText != null) {
368                 throw new BuildException("Choose either script text or script attribute but not both.");
369             }
370             
371             if (port <= 0) {
372                 throw new BuildException("'port' attribute must be set on AddUser to the port against which the script should run.");
373             }
374         }
375         
376         /**
377          * Creates a user.
378          * @throws BuildException
379          */
380         void execute() throws BuildException {
381             validate();
382             try {
383                 final File scriptFile = getScript();
384                 final Reader reader;
385                 if (scriptFile == null) {
386                     reader = new StringReader(scriptText);
387                 } else {
388                     reader = new FileReader(scriptFile);
389                 }
390                 final ScriptedUserAdder adder = new ScriptedUserAdder(getHost(), getPort(), MailProtocolTestTask.this);
391                 adder.addUser(getUser(), getPasswd(), reader);
392             } catch (Exception e) {
393                 log(e.getMessage(), Project.MSG_ERR);
394                 throw new BuildException("User addition failed: \n" + e.getMessage(), e);
395             }
396         } 
397     }
398 
399     public void note(String message) {
400         if (quiet) {
401             log(message, Project.MSG_DEBUG);
402         } else {
403             log(message, Project.MSG_INFO);
404         }
405     }
406 
407     public void debug(char character) {
408         log("'" + character + "'", Project.MSG_DEBUG);
409     }
410 
411     public void debug(String message) {
412         log(message, Project.MSG_DEBUG);
413     }
414 }