1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.impl.wsdl.teststeps.assertions;
14
15 import java.awt.BorderLayout;
16 import java.awt.event.ActionEvent;
17
18 import javax.swing.AbstractAction;
19 import javax.swing.Action;
20 import javax.swing.BorderFactory;
21 import javax.swing.JButton;
22 import javax.swing.JDialog;
23 import javax.swing.JLabel;
24 import javax.swing.JOptionPane;
25 import javax.swing.JPanel;
26 import javax.swing.JScrollPane;
27 import javax.swing.JSplitPane;
28 import javax.swing.JTextArea;
29
30 import org.apache.log4j.Logger;
31 import org.apache.xmlbeans.XmlAnySimpleType;
32 import org.apache.xmlbeans.XmlCursor;
33 import org.apache.xmlbeans.XmlObject;
34 import org.apache.xmlbeans.XmlOptions;
35 import org.custommonkey.xmlunit.XMLAssert;
36 import org.w3c.dom.Element;
37 import org.w3c.dom.Node;
38
39 import com.eviware.soapui.SoapUI;
40 import com.eviware.soapui.config.RequestAssertionConfig;
41 import com.eviware.soapui.impl.wsdl.teststeps.WsdlAssertion;
42 import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequest;
43 import com.eviware.soapui.support.UISupport;
44 import com.eviware.soapui.support.XmlUtils;
45 import com.jgoodies.forms.builder.ButtonBarBuilder;
46
47 /***
48 * Assertion that matches a specified XPath expression and its expected result against
49 * the associated WsdlTestRequests response message
50 *
51 * @author Ole.Matzura
52 */
53
54 public class XPathContainsAssertion extends WsdlAssertion
55 {
56 private final static Logger log = Logger.getLogger( XPathContainsAssertion.class );
57 private String content;
58 private String path;
59 private JDialog configurationDialog;
60 private JTextArea pathArea;
61 private JTextArea contentArea;
62
63 public XPathContainsAssertion(RequestAssertionConfig assertionConfig, WsdlTestRequest request)
64 {
65 super(assertionConfig, request);
66
67 XmlObject[] paths = getConfiguration().selectPath( "$this/path" );
68 if( paths.length == 1 )
69 path = paths[0].newCursor().getTextValue();
70
71 paths = getConfiguration().selectPath( "$this/content" );
72 if( paths.length == 1 )
73 content = paths[0].newCursor().getTextValue();
74 }
75
76 public String getContent()
77 {
78 return content;
79 }
80
81 public void setContent(String content)
82 {
83 this.content = content;
84 }
85
86 public String getPath()
87 {
88 return path;
89 }
90
91 public void setPath(String path)
92 {
93 this.path = path;
94 }
95
96 public String assertRequest(WsdlTestRequest request) throws AssertionException
97 {
98 return assertResponse( request.getResponseContent() );
99 }
100
101 public String assertResponse( String response ) throws AssertionException
102 {
103 try
104 {
105 if( path == null ) return "Missing path for XPath assertion";
106 if( content == null ) return "Missing content for XPath assertion";
107
108 XmlObject xml = XmlObject.Factory.parse( response );
109 XmlObject[] items = xml.selectPath( path );
110
111 XmlObject contentObj = null;
112
113 try
114 {
115 contentObj = XmlObject.Factory.parse(content);
116 }
117 catch (Exception e)
118 {
119 }
120
121 if( items.length == 0 )
122 throw new Exception( "Missing content for xpath [" + path + "]" );
123
124 XmlOptions options = new XmlOptions();
125 options.setSavePrettyPrint();
126 options.setSaveOuter();
127
128 for( int c = 0; c < items.length; c++ )
129 {
130 try
131 {
132 if (contentObj == null)
133 {
134 if( items[c] instanceof XmlAnySimpleType )
135 {
136 XMLAssert.assertEquals(content, ((XmlAnySimpleType)items[c]).getStringValue() );
137 }
138 else
139 {
140 Node domNode = items[c].getDomNode();
141 if (domNode.getNodeType() == Node.ELEMENT_NODE)
142 {
143 XMLAssert.assertEquals(content, XmlUtils.getElementText((Element) domNode));
144 }
145 else
146 {
147 XMLAssert.assertEquals(content, domNode.getNodeValue());
148 }
149 }
150 }
151 else
152 {
153 XMLAssert.assertXMLEqual(contentObj.xmlText(options), items[c].xmlText(options));
154 }
155
156 break;
157 }
158 catch (Throwable e)
159 {
160 if( c == items.length-1 )
161 throw e;
162 }
163 }
164 }
165 catch (Throwable e)
166 {
167 String msg = "XPathContains assertion failed for path [" + path +
168 "] : " + e.getClass().getSimpleName() + ":" + e.getMessage();
169
170 throw new AssertionException( new AssertionError(msg) );
171 }
172
173 return "Response matches content for [" + path + "]";
174 }
175
176 public void configure()
177 {
178 if( configurationDialog == null )
179 buildConfigurationDialog();
180
181 pathArea.setText( path );
182 contentArea.setText( content );
183
184 SoapUI.centerDialog( configurationDialog );
185 configurationDialog.setVisible( true );
186 }
187
188 private void buildConfigurationDialog()
189 {
190 configurationDialog = new JDialog( SoapUI.getInstance().getFrame() );
191 configurationDialog.setTitle("XPath Match configuration" );
192
193 JPanel contentPanel = new JPanel( new BorderLayout() );
194 JLabel label = new JLabel( "<html><b>Specify xpath expression and matching content below</b><br>" +
195 "declare namespaces with <code>declare namespace <prefix>='<namespace>';</code></html>" );
196 label.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
197 contentPanel.add( label, BorderLayout.NORTH );
198
199 JSplitPane splitPane = UISupport.createVerticalSplit();
200 pathArea = new JTextArea();
201 splitPane.setTopComponent( new JScrollPane( pathArea ));
202
203 contentArea = new JTextArea();
204 splitPane.setBottomComponent( new JScrollPane( contentArea ));
205 splitPane.setDividerLocation( 100 );
206 splitPane.setBorder(BorderFactory.createEmptyBorder( 0, 3, 0, 3 ));
207
208 contentPanel.add( splitPane, BorderLayout.CENTER );
209
210 ButtonBarBuilder builder = new ButtonBarBuilder();
211
212 builder.addFixed( new JButton( new SelectFromCurrentAction() ));
213 builder.addRelatedGap();
214 builder.addFixed( new JButton( new TestPathAction() ));
215 builder.addRelatedGap();
216 builder.addFixed( new JButton( new DeclareNamespacesFromCurrentAction()));
217
218 builder.addGlue();
219 builder.addFixed( new JButton( new OkAction() ));
220 builder.addRelatedGap();
221 builder.addFixed( new JButton( new CancelAction() ));
222 builder.setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ));
223
224 contentPanel.add( builder.getPanel(), BorderLayout.SOUTH );
225
226 configurationDialog.setContentPane( contentPanel );
227 configurationDialog.setSize(500, 400);
228
229 configurationDialog.setModal( false );
230 }
231
232 public XmlObject createConfiguration()
233 {
234 XmlObject config = XmlObject.Factory.newInstance();
235 XmlCursor cursor = config.newCursor();
236 cursor.toNextToken();
237 cursor.insertElementWithText( "path", path );
238 cursor.insertElementWithText( "content", content );
239 cursor.dispose();
240 return config;
241 }
242
243 public boolean isConfigurable()
244 {
245 return true;
246 }
247
248 public class OkAction extends AbstractAction
249 {
250 public OkAction()
251 {
252 super( "Save" );
253 }
254
255 public void actionPerformed(ActionEvent arg0)
256 {
257 setPath( pathArea.getText().trim() );
258 setContent( contentArea.getText().trim() );
259 setConfiguration( createConfiguration() );
260
261 configurationDialog.setVisible( false );
262 }
263 }
264
265 public class CancelAction extends AbstractAction
266 {
267 public CancelAction()
268 {
269 super( "Cancel" );
270 }
271
272 public void actionPerformed(ActionEvent arg0)
273 {
274 configurationDialog.setVisible( false );
275 }
276 }
277
278 public class DeclareNamespacesFromCurrentAction extends AbstractAction
279 {
280 public DeclareNamespacesFromCurrentAction()
281 {
282 super( "Declare" );
283 putValue( Action.SHORT_DESCRIPTION, "Add namespace declaration from current response to xpath expression");
284 }
285
286 public void actionPerformed(ActionEvent arg0)
287 {
288 try
289 {
290 String responseContent = ((WsdlTestRequest) getRequest()).getResponseContent();
291 if( responseContent == null || responseContent.trim().length() == 0 )
292 return;
293
294 pathArea.setText( XmlUtils.declareXPathNamespaces(responseContent ) + pathArea.getText() );
295 }
296 catch (Exception e)
297 {
298 log.error( e.getMessage() );
299 }
300
301 }
302 }
303
304 public class TestPathAction extends AbstractAction
305 {
306 public TestPathAction()
307 {
308 super( "Test" );
309 }
310
311 public void actionPerformed(ActionEvent arg0)
312 {
313 String oldPath = getPath();
314 String oldContent = getContent();
315
316 setPath( pathArea.getText().trim() );
317 setContent( contentArea.getText().trim() );
318
319 try
320 {
321 String msg = assertRequest( ((WsdlTestRequest) getRequest()) );
322 JOptionPane.showMessageDialog( SoapUI.getInstance().getFrame(),
323 msg, "Success", JOptionPane.INFORMATION_MESSAGE );
324 }
325 catch (AssertionException e)
326 {
327 JOptionPane.showMessageDialog( SoapUI.getInstance().getFrame(),
328 e.getMessage(), "Assertion Failed", JOptionPane.ERROR_MESSAGE );
329 }
330
331 setPath( oldPath );
332 setContent( oldContent );
333 }
334 }
335
336 public class SelectFromCurrentAction extends AbstractAction
337 {
338 private XmlOptions options;
339
340 public SelectFromCurrentAction()
341 {
342 super( "Select from current" );
343
344 options = new XmlOptions();
345 options.setSavePrettyPrint();
346 options.setSaveOuter();
347 options.setSaveAggressiveNamespaces();
348 }
349
350 public void actionPerformed(ActionEvent arg0)
351 {
352 try
353 {
354 XmlObject xml = XmlObject.Factory
355 .parse(((WsdlTestRequest) getRequest()).getResponseContent());
356
357 String txt = pathArea.getSelectedText();
358 if( txt == null ) txt = pathArea.getText();
359
360 XmlObject[] items = xml.selectPath(txt.trim());
361
362 contentArea.setText("");
363
364 if( items.length == 0 )
365 {
366 JOptionPane.showMessageDialog( SoapUI.getInstance().getFrame(),
367 "No match in current response", "Error", JOptionPane.ERROR_MESSAGE );
368 }
369 else if( items.length > 1 )
370 {
371 JOptionPane.showMessageDialog( SoapUI.getInstance().getFrame(),
372 "More than one match in current response", "Error", JOptionPane.ERROR_MESSAGE );
373 }
374 else
375 {
376 if( items[0] instanceof XmlAnySimpleType )
377 {
378 contentArea.setText( ((XmlAnySimpleType)items[0]).getStringValue() );
379 }
380 else
381 {
382 Node domNode = items[0].getDomNode();
383 if (domNode.getNodeType() == Node.ELEMENT_NODE)
384 {
385 contentArea.setText( items[0].xmlText(options));
386 }
387 else
388 {
389 contentArea.setText( domNode.getNodeValue());
390 }
391 }
392 }
393 }
394 catch (Throwable e)
395 {
396 JOptionPane.showMessageDialog( SoapUI.getInstance().getFrame(),
397 e.getMessage(), "Error", JOptionPane.OK_OPTION );
398 }
399 }
400
401 }
402 }