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 }
122
123 if( items.length == 0 )
124 throw new Exception( "Missing content for xpath [" + path + "]" );
125
126 XmlOptions options = new XmlOptions();
127 options.setSavePrettyPrint();
128 options.setSaveOuter();
129
130 for( int c = 0; c < items.length; c++ )
131 {
132 try
133 {
134 if (contentObj == null)
135 {
136 if( items[c] instanceof XmlAnySimpleType )
137 {
138 XMLAssert.assertEquals(content, ((XmlAnySimpleType)items[c]).getStringValue() );
139 }
140 else
141 {
142 Node domNode = items[c].getDomNode();
143 if (domNode.getNodeType() == Node.ELEMENT_NODE)
144 {
145 XMLAssert.assertEquals(content, XmlUtils.getElementText((Element) domNode));
146 }
147 else
148 {
149 XMLAssert.assertEquals(content, domNode.getNodeValue());
150 }
151 }
152 }
153 else
154 {
155 XMLAssert.assertXMLEqual(contentObj.xmlText(options), items[c].xmlText(options));
156 }
157
158 break;
159 }
160 catch (Throwable e)
161 {
162 if( c == items.length-1 )
163 throw e;
164 }
165 }
166 }
167 catch (Throwable e)
168 {
169 String msg = "XPathContains assertion failed for path [" + path +
170 "] : " + e.getClass().getSimpleName() + ":" + e.getMessage();
171
172 throw new AssertionException( new AssertionError(msg) );
173 }
174
175 return "Response matches content for [" + path + "]";
176 }
177
178 public void configure()
179 {
180 if( configurationDialog == null )
181 buildConfigurationDialog();
182
183 pathArea.setText( path );
184 contentArea.setText( content );
185
186 UISupport.showDialog( configurationDialog );
187 }
188
189 private void buildConfigurationDialog()
190 {
191 configurationDialog = new JDialog( SoapUI.getInstance().getFrame() );
192 configurationDialog.setTitle("XPath Match configuration" );
193
194 JPanel contentPanel = new JPanel( new BorderLayout() );
195 JLabel label = new JLabel( "<html><b>Specify xpath expression and matching content below</b><br>" +
196 "declare namespaces with <code>declare namespace <prefix>='<namespace>';</code></html>" );
197 label.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
198 contentPanel.add( label, BorderLayout.NORTH );
199
200 JSplitPane splitPane = UISupport.createVerticalSplit();
201 pathArea = new JTextArea();
202 splitPane.setTopComponent( new JScrollPane( pathArea ));
203
204 contentArea = new JTextArea();
205 splitPane.setBottomComponent( new JScrollPane( contentArea ));
206 splitPane.setDividerLocation( 100 );
207 splitPane.setBorder(BorderFactory.createEmptyBorder( 0, 3, 0, 3 ));
208
209 contentPanel.add( splitPane, BorderLayout.CENTER );
210
211 ButtonBarBuilder builder = new ButtonBarBuilder();
212
213 builder.addFixed( new JButton( new SelectFromCurrentAction() ));
214 builder.addRelatedGap();
215 builder.addFixed( new JButton( new TestPathAction() ));
216 builder.addRelatedGap();
217 builder.addFixed( new JButton( new DeclareNamespacesFromCurrentAction()));
218
219 builder.addGlue();
220 builder.addFixed( new JButton( new OkAction() ));
221 builder.addRelatedGap();
222 builder.addFixed( new JButton( new CancelAction() ));
223 builder.setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ));
224
225 contentPanel.add( builder.getPanel(), BorderLayout.SOUTH );
226
227 configurationDialog.setContentPane( contentPanel );
228 configurationDialog.setSize(500, 400);
229
230 configurationDialog.setModal( false );
231 }
232
233 public XmlObject createConfiguration()
234 {
235 XmlObject config = XmlObject.Factory.newInstance();
236 XmlCursor cursor = config.newCursor();
237 cursor.toNextToken();
238 cursor.insertElementWithText( "path", path );
239 cursor.insertElementWithText( "content", content );
240 cursor.dispose();
241 return config;
242 }
243
244 public boolean isConfigurable()
245 {
246 return true;
247 }
248
249 public class OkAction extends AbstractAction
250 {
251 public OkAction()
252 {
253 super( "Save" );
254 }
255
256 public void actionPerformed(ActionEvent arg0)
257 {
258 setPath( pathArea.getText().trim() );
259 setContent( contentArea.getText().trim() );
260 setConfiguration( createConfiguration() );
261
262 configurationDialog.setVisible( false );
263 }
264 }
265
266 public class CancelAction extends AbstractAction
267 {
268 public CancelAction()
269 {
270 super( "Cancel" );
271 }
272
273 public void actionPerformed(ActionEvent arg0)
274 {
275 configurationDialog.setVisible( false );
276 }
277 }
278
279 public class DeclareNamespacesFromCurrentAction extends AbstractAction
280 {
281 public DeclareNamespacesFromCurrentAction()
282 {
283 super( "Declare" );
284 putValue( Action.SHORT_DESCRIPTION, "Add namespace declaration from current response to xpath expression");
285 }
286
287 public void actionPerformed(ActionEvent arg0)
288 {
289 try
290 {
291 String responseContent = ((WsdlTestRequest) getRequest()).getResponseContent();
292 if( responseContent == null || responseContent.trim().length() == 0 )
293 return;
294
295 pathArea.setText( XmlUtils.declareXPathNamespaces(responseContent ) + pathArea.getText() );
296 }
297 catch (Exception e)
298 {
299 log.error( e.getMessage() );
300 }
301
302 }
303 }
304
305 public class TestPathAction extends AbstractAction
306 {
307 public TestPathAction()
308 {
309 super( "Test" );
310 }
311
312 public void actionPerformed(ActionEvent arg0)
313 {
314 String oldPath = getPath();
315 String oldContent = getContent();
316
317 setPath( pathArea.getText().trim() );
318 setContent( contentArea.getText().trim() );
319
320 try
321 {
322 String msg = assertRequest( ((WsdlTestRequest) getRequest()) );
323 JOptionPane.showMessageDialog( SoapUI.getInstance().getFrame(),
324 msg, "Success", JOptionPane.INFORMATION_MESSAGE );
325 }
326 catch (AssertionException e)
327 {
328 JOptionPane.showMessageDialog( SoapUI.getInstance().getFrame(),
329 e.getMessage(), "Assertion Failed", JOptionPane.ERROR_MESSAGE );
330 }
331
332 setPath( oldPath );
333 setContent( oldContent );
334 }
335 }
336
337 public class SelectFromCurrentAction extends AbstractAction
338 {
339 private XmlOptions options;
340
341 public SelectFromCurrentAction()
342 {
343 super( "Select from current" );
344
345 options = new XmlOptions();
346 options.setSavePrettyPrint();
347 options.setSaveOuter();
348 options.setSaveAggressiveNamespaces();
349 }
350
351 public void actionPerformed(ActionEvent arg0)
352 {
353 try
354 {
355 XmlObject xml = XmlObject.Factory
356 .parse(((WsdlTestRequest) getRequest()).getResponseContent());
357
358 String txt = pathArea.getSelectedText();
359 if( txt == null ) txt = pathArea.getText();
360
361 XmlObject[] items = xml.selectPath(txt.trim());
362
363 contentArea.setText("");
364
365 if( items.length == 0 )
366 {
367 JOptionPane.showMessageDialog( SoapUI.getInstance().getFrame(),
368 "No match in current response", "Error", JOptionPane.ERROR_MESSAGE );
369 }
370 else if( items.length > 1 )
371 {
372 JOptionPane.showMessageDialog( SoapUI.getInstance().getFrame(),
373 "More than one match in current response", "Error", JOptionPane.ERROR_MESSAGE );
374 }
375 else
376 {
377 if( items[0] instanceof XmlAnySimpleType )
378 {
379 contentArea.setText( ((XmlAnySimpleType)items[0]).getStringValue() );
380 }
381 else
382 {
383 Node domNode = items[0].getDomNode();
384 if (domNode.getNodeType() == Node.ELEMENT_NODE)
385 {
386 contentArea.setText( items[0].xmlText(options));
387 }
388 else
389 {
390 contentArea.setText( domNode.getNodeValue());
391 }
392 }
393 }
394 }
395 catch (Throwable e)
396 {
397 JOptionPane.showMessageDialog( SoapUI.getInstance().getFrame(),
398 e.getMessage(), "Error", JOptionPane.OK_OPTION );
399 }
400 }
401
402 }
403 }