[ https://issues.apache.org/jira/browse/WW-5517?focusedWorklogId=953088&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-953088 ]
ASF GitHub Bot logged work on WW-5517: -------------------------------------- Author: ASF GitHub Bot Created on: 20/Jan/25 02:20 Start Date: 20/Jan/25 02:20 Worklog Time Spent: 10m Work Description: kusalk commented on code in PR #1187: URL: https://github.com/apache/struts/pull/1187#discussion_r1921711368 ########## core/src/test/java/org/apache/struts2/views/jsp/ui/DebugTagTest.java: ########## @@ -198,14 +197,14 @@ public void testTagAttributeOverrideDevModeFalse_clearTagStateSet() throws Excep freshTag.setPerformClearTagStateForTagPoolingServers(true); freshTag.setPageContext(pageContext); assertTrue("Tag state after doEndTag() and explicit tag state clearing is inequal to new Tag with pageContext/parent set. " + - "May indicate that clearTagStateForTagPoolingServers() calls are not working properly.", + "May indicate that clearTagStateForTagPoolingServers() calls are not working properly.", strutsBodyTagsAreReflectionEqual(tag, freshTag)); PrepareOperations.clearDevModeOverride(); // Clear DevMode override. Avoid ThreadLocal side-effects if test thread re-used. } private void setDevMode(final boolean devMode) { - setStrutsConstant(new HashMap<String, String>() {{ + setStrutsConstant(new HashMap<>() {{ Review Comment: Nit: `Map#of` or `Collections#singletonMap` ########## core/src/test/java/org/apache/struts2/interceptor/debugging/DebuggingInterceptorTest.java: ########## @@ -0,0 +1,552 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.struts2.interceptor.debugging; + +import org.apache.struts2.ActionContext; +import org.apache.struts2.StrutsJUnit4InternalTestCase; +import org.apache.struts2.TestAction; +import org.apache.struts2.dispatcher.DispatcherConstants; +import org.apache.struts2.dispatcher.HttpParameters; +import org.apache.struts2.dispatcher.RequestMap; +import org.apache.struts2.dispatcher.SessionMap; +import org.apache.struts2.mock.MockActionInvocation; +import org.apache.struts2.util.ValueStack; +import org.assertj.core.util.Maps; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockHttpSession; + +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +public class DebuggingInterceptorTest extends StrutsJUnit4InternalTestCase { + + private DebuggingInterceptor interceptor; + private MockActionInvocation invocation; + private MockHttpServletRequest request; + private MockHttpServletResponse response; + private ActionContext context; + + @Test + public void noDevMode() throws Exception { + interceptor.intercept(invocation); + assertThat(invocation.getResultCode()).isEqualTo("mock"); + assertThat(response.getContentAsString()).isEmpty(); + } + + @Test + public void debugXml() throws Exception { + interceptor.setDevMode("true"); + context.withParameters(HttpParameters.create(Maps.newHashMap("debug", "xml")).build()); + + interceptor.intercept(invocation); + + assertThat(response.getContentAsString()).isEqualToIgnoringWhitespace(""" + <debug> + <parameters/> + <context/> + <request/> + <session/> + <valueStack> + <value> + <action> + <actionErrors/> + <actionMessages/> + <class>class org.apache.struts2.TestAction</class> + <fieldErrors/> + <locale> + <ISO3Country>USA</ISO3Country> + <ISO3Language>eng</ISO3Language> + <class>class java.util.Locale</class> + <country>US</country> + <displayCountry>United States</displayCountry> + <displayLanguage>English</displayLanguage> + <displayName>English (United States)</displayName> + <displayScript></displayScript> + <displayVariant></displayVariant> + <extensionKeys/> + <language>en</language> + <script></script> + <unicodeLocaleAttributes/> + <unicodeLocaleKeys/> + <variant></variant> + </locale> + <status> + <class>class org.apache.struts2.SomeEnum</class> + <declaringClass>class org.apache.struts2.SomeEnum</declaringClass> + <displayName>completed</displayName> + <name>COMPLETED</name> + </status> + <statusList> + <value> + <class>class org.apache.struts2.SomeEnum</class> + <declaringClass>class org.apache.struts2.SomeEnum</declaringClass> + <displayName>init</displayName> + <name>INIT</name> + </value> + <value> + <class>class org.apache.struts2.SomeEnum</class> + <declaringClass>class org.apache.struts2.SomeEnum</declaringClass> + <displayName>completed</displayName> + <name>COMPLETED</name> + </value> + </statusList> + <texts> + <baseBundleName>org.apache.struts2.TestAction</baseBundleName> + <class>class java.util.PropertyResourceBundle</class> + <keys> + <class>class sun.util.ResourceBundleEnumeration</class> + </keys> + <locale> + <ISO3Country></ISO3Country> + <ISO3Language></ISO3Language> + <class>class java.util.Locale</class> + <country></country> + <displayCountry></displayCountry> + <displayLanguage></displayLanguage> + <displayName></displayName> + <displayScript></displayScript> + <displayVariant></displayVariant> + <extensionKeys/> + <language></language> + <script></script> + <unicodeLocaleAttributes/> + <unicodeLocaleKeys/> + <variant></variant> + </locale> + </texts> + </action> + <org.apache.struts2.util.OgnlValueStack.MAP_IDENTIFIER_KEY></org.apache.struts2.util.OgnlValueStack.MAP_IDENTIFIER_KEY> + </value> + <value> + <class>class org.apache.struts2.text.DefaultTextProvider</class> + </value> + </valueStack> + </debug> + """); + } + + @Test + public void debugXmlWithConsole() throws Exception { + interceptor.setDevMode("true"); + context.withParameters(HttpParameters.create(Maps.newHashMap("debug", "console")).build()); + interceptor.setEnableXmlWithConsole(true); + + interceptor.intercept(invocation); + + assertThat(response.getContentAsString()).isEqualToIgnoringWhitespace(""" + <!DOCTYPE html> + <html> + <head> + <script> + var baseUrl = "/static"; + window.open(baseUrl+"/webconsole.html", 'OGNL Console','width=500,height=450,status=no,toolbar=no,menubar=no'); + </script> + </head> + <body> + <pre> + &lt;debug&gt; + &lt;parameters/&gt; + &lt;context/&gt; + &lt;request/&gt; + &lt;session/&gt; + &lt;valueStack&gt; + &lt;value&gt; + &lt;action&gt; + &lt;actionErrors/&gt; + &lt;actionMessages/&gt; + &lt;class&gt;class org.apache.struts2.TestAction&lt;/class&gt; + &lt;fieldErrors/&gt; + &lt;locale&gt; + &lt;ISO3Country&gt;USA&lt;/ISO3Country&gt; + &lt;ISO3Language&gt;eng&lt;/ISO3Language&gt; + &lt;class&gt;class java.util.Locale&lt;/class&gt; + &lt;country&gt;US&lt;/country&gt; + &lt;displayCountry&gt;United States&lt;/displayCountry&gt; + &lt;displayLanguage&gt;English&lt;/displayLanguage&gt; + &lt;displayName&gt;English (United States)&lt;/displayName&gt; + &lt;displayScript&gt;&lt;/displayScript&gt; + &lt;displayVariant&gt;&lt;/displayVariant&gt; + &lt;extensionKeys/&gt; + &lt;language&gt;en&lt;/language&gt; + &lt;script&gt;&lt;/script&gt; + &lt;unicodeLocaleAttributes/&gt; + &lt;unicodeLocaleKeys/&gt; + &lt;variant&gt;&lt;/variant&gt; + &lt;/locale&gt; + &lt;status&gt; + &lt;class&gt;class org.apache.struts2.SomeEnum&lt;/class&gt; + &lt;declaringClass&gt;class org.apache.struts2.SomeEnum&lt;/declaringClass&gt; + &lt;displayName&gt;completed&lt;/displayName&gt; + &lt;name&gt;COMPLETED&lt;/name&gt; + &lt;/status&gt; + &lt;statusList&gt; + &lt;value&gt; + &lt;class&gt;class org.apache.struts2.SomeEnum&lt;/class&gt; + &lt;declaringClass&gt;class org.apache.struts2.SomeEnum&lt;/declaringClass&gt; + &lt;displayName&gt;init&lt;/displayName&gt; + &lt;name&gt;INIT&lt;/name&gt; + &lt;/value&gt; + &lt;value&gt; + &lt;class&gt;class org.apache.struts2.SomeEnum&lt;/class&gt; + &lt;declaringClass&gt;class org.apache.struts2.SomeEnum&lt;/declaringClass&gt; + &lt;displayName&gt;completed&lt;/displayName&gt; + &lt;name&gt;COMPLETED&lt;/name&gt; + &lt;/value&gt; + &lt;/statusList&gt; + &lt;texts&gt; + &lt;baseBundleName&gt;org.apache.struts2.TestAction&lt;/baseBundleName&gt; + &lt;class&gt;class java.util.PropertyResourceBundle&lt;/class&gt; + &lt;keys&gt; + &lt;class&gt;class sun.util.ResourceBundleEnumeration&lt;/class&gt; + &lt;/keys&gt; + &lt;locale&gt; + &lt;ISO3Country&gt;&lt;/ISO3Country&gt; + &lt;ISO3Language&gt;&lt;/ISO3Language&gt; + &lt;class&gt;class java.util.Locale&lt;/class&gt; + &lt;country&gt;&lt;/country&gt; + &lt;displayCountry&gt;&lt;/displayCountry&gt; + &lt;displayLanguage&gt;&lt;/displayLanguage&gt; + &lt;displayName&gt;&lt;/displayName&gt; + &lt;displayScript&gt;&lt;/displayScript&gt; + &lt;displayVariant&gt;&lt;/displayVariant&gt; + &lt;extensionKeys/&gt; + &lt;language&gt;&lt;/language&gt; + &lt;script&gt;&lt;/script&gt; + &lt;unicodeLocaleAttributes/&gt; + &lt;unicodeLocaleKeys/&gt; + &lt;variant&gt;&lt;/variant&gt; + &lt;/locale&gt; + &lt;/texts&gt; + &lt;/action&gt; + &lt;org.apache.struts2.util.OgnlValueStack.MAP_IDENTIFIER_KEY&gt;&lt;/org.apache.struts2.util.OgnlValueStack.MAP_IDENTIFIER_KEY&gt; + &lt;/value&gt; + &lt;value&gt; + &lt;class&gt;class org.apache.struts2.text.DefaultTextProvider&lt;/class&gt; + &lt;/value&gt; + &lt;/valueStack&gt; + &lt;/debug&gt; + </pre> + </body> + </html> + """); + } + + @Test + public void debugConsole() throws Exception { + interceptor.setDevMode("true"); + context.withParameters(HttpParameters.create(Maps.newHashMap("debug", "console")).build()); + + interceptor.intercept(invocation); + + assertThat(response.getContentAsString()).isEqualToIgnoringWhitespace(""" + <!DOCTYPE html> + <html> + <head> + <script> + var baseUrl = "/static"; + window.open(baseUrl+"/webconsole.html", 'OGNL Console','width=500,height=450,status=no,toolbar=no,menubar=no'); + </script> + </head> + <body> + <pre> + + </pre> + </body> + </html> + """); + } + + @Test + public void debugCommand() throws Exception { + interceptor.setDevMode("true"); + Map<String, Object> params = new HashMap<>() {{ + put("debug", "command"); + put("expression", "1+1"); + }}; + context.withParameters(HttpParameters.create(params).build()); + + interceptor.intercept(invocation); + + assertThat(response.getContentAsString()).isEqualToIgnoringWhitespace("2"); + } + + @Test + public void debugBrowser() throws Exception { + interceptor.setDevMode("true"); + context.withParameters(HttpParameters.create(Maps.newHashMap("debug", "browser")).build()); + + interceptor.intercept(invocation); + invocation.invoke(); + + assertThat(response.getContentAsString()).isEqualToIgnoringWhitespace(""" + <!DOCTYPE html> + <html lang="en"> + <style> + .debugTable { + border-style: solid; + border-width: 1px; + } + + .debugTable td { + border-style: solid; + border-width: 1px; + } + + .nameColumn { + background-color:#CCDDFF; + } + + .valueColumn { + background-color: #CCFFCC; + } + + .nullValue { + background-color: #FF0000; + } + + .typeColumn { + background-color: white; + } + + .emptyCollection { + background-color: #EEEEEE; + } + </style> + + <script> + function expand(src, path) { + let baseUrl = location.href; + const i = baseUrl.indexOf('&object='); + baseUrl = (i > 0 ? baseUrl.substring(0, i) : baseUrl) + "&object=" + path; + if (baseUrl.indexOf("decorate") < 0) { + baseUrl += "&decorate=false"; + } + + const request = new XMLHttpRequest(); + request.open('GET', baseUrl, true); + request.onreadystatechange = function() { + if (this.readyState === 4) { + if (this.status >= 200 && this.status < 400) { + const div = document.createElement('div'); + console.log(this.responseText); + div.innerHTML = this.responseText; + src.parentNode.appendChild(div); + + src.innerHTML = "Collapse"; + const oldOnclick = src.onclick; + src.onclick = function() { + src.innerHTML = "Expand"; + src.parentNode.removeChild(div); + src.onclick = oldOnclick; + }; + } + } + }; + request.send(); + } + </script> + + <body> + <table class="debugTable"> + <tr> + <td class="nameColumn">container</td> + <td class="valueColumn">There is no read method for container</td> + <td class="typeColumn">java.lang.String</td> + </tr> + <tr> + <td class="nameColumn">foo</td> + <td class="nullValue">null</td> + <td class="nullValue">unknown</td> + </tr> + <tr> + <td class="nameColumn">intList</td> + <td class="nullValue">null</td> + <td class="nullValue">unknown</td> + </tr> + <tr> + <td class="nameColumn">locale</td> + <td class="valueColumn"> + <a onclick="expand(this, 'action["locale"]')" href="javascript://nop/">Expand</a> + </td> + <td class="typeColumn">java.util.Locale</td> + </tr> + <tr> + <td class="nameColumn">result</td> + <td class="nullValue">null</td> + <td class="nullValue">unknown</td> + </tr> + <tr> + <td class="nameColumn">collection2</td> + <td class="nullValue">null</td> + <td class="nullValue">unknown</td> + </tr> + <tr> + <td class="nameColumn">someBool</td> + <td class="nullValue">null</td> + <td class="nullValue">unknown</td> + </tr> + <tr> + <td class="nameColumn">array</td> + <td class="nullValue">null</td> + <td class="nullValue">unknown</td> + </tr> + <tr> + <td class="nameColumn">fooInt</td> + <td class="nullValue">null</td> + <td class="nullValue">unknown</td> + </tr> + <tr> + <td class="nameColumn">id</td> + <td class="nullValue">null</td> + <td class="nullValue">unknown</td> + </tr> + <tr> + <td class="nameColumn">map</td> + <td class="nullValue">null</td> + <td class="nullValue">unknown</td> + </tr> + <tr> + <td class="nameColumn">actionErrors</td> + <td class="emptyCollection">empty</td> + <td class="typeColumn">java.util.LinkedList</td> + </tr> + <tr> + <td class="nameColumn">objectArray</td> + <td class="nullValue">null</td> + <td class="nullValue">unknown</td> + </tr> + <tr> + <td class="nameColumn">fieldErrors</td> + <td class="emptyCollection">empty</td> + <td class="typeColumn">java.util.LinkedHashMap</td> + </tr> + <tr> + <td class="nameColumn">collection</td> + <td class="nullValue">null</td> + <td class="nullValue">unknown</td> + </tr> + <tr> + <td class="nameColumn">floatNumber</td> + <td class="nullValue">null</td> + <td class="nullValue">unknown</td> + </tr> + <tr> + <td class="nameColumn">list</td> + <td class="nullValue">null</td> + <td class="nullValue">unknown</td> + </tr> + <tr> + <td class="nameColumn">enumList</td> + <td class="nullValue">null</td> + <td class="nullValue">unknown</td> + </tr> + <tr> + <td class="nameColumn">actionMessages</td> + <td class="emptyCollection">empty</td> + <td class="typeColumn">java.util.LinkedList</td> + </tr> + <tr> + <td class="nameColumn">statusList</td> + <td class="valueColumn"> + <a onclick="expand(this, 'action["statusList"]')" href="javascript://nop/">Expand</a> + </td> + <td class="typeColumn">java.util.Arrays$ArrayList</td> + </tr> + <tr> + <td class="nameColumn">texts</td> + <td class="valueColumn"> + <a onclick="expand(this, 'action["texts"]')" href="javascript://nop/">Expand</a> + </td> + <td class="typeColumn">java.util.PropertyResourceBundle</td> + </tr> + <tr> + <td class="nameColumn">list3</td> + <td class="nullValue">null</td> + <td class="nullValue">unknown</td> + </tr> + <tr> + <td class="nameColumn">list2</td> + <td class="nullValue">null</td> + <td class="nullValue">unknown</td> + </tr> + <tr> + <td class="nameColumn">user</td> + <td class="nullValue">null</td> + <td class="nullValue">unknown</td> + </tr> + <tr> + <td class="nameColumn">status</td> + <td class="valueColumn"> + <a onclick="expand(this, 'action["status"]')" href="javascript://nop/">Expand</a> + </td> + <td class="typeColumn">org.apache.struts2.SomeEnum</td> + </tr> + </table> + </body> + </html> + """); + } + + @Before + public void before() { + request = new MockHttpServletRequest(); + request.setSession(new MockHttpSession()); + response = new MockHttpServletResponse(); + + ValueStack valueStack = dispatcher.getValueStackFactory().createValueStack(); + + context = valueStack.getActionContext() + .withServletContext(servletContext) + .withServletRequest(request) + .withServletResponse(response) + .withSession(new SessionMap(request)) + .with(DispatcherConstants.REQUEST, new RequestMap(request)); + + interceptor = container.inject(DebuggingInterceptor.class); + interceptor.init(); + + invocation = new MockActionInvocation(); + invocation.setResultCode("mock"); + invocation.setInvocationContext(context); + invocation.setAction(new TestAction()); + invocation.setStack(valueStack); + + valueStack.set("action", invocation.getAction()); + + context = context.withActionInvocation(invocation).bind(); + } + + @After + public void after() { Review Comment: Nit: looks redundant Issue Time Tracking ------------------- Worklog Id: (was: 953088) Remaining Estimate: 0h Time Spent: 10m > The debug Struts tag throws an error. > ------------------------------------- > > Key: WW-5517 > URL: https://issues.apache.org/jira/browse/WW-5517 > Project: Struts 2 > Issue Type: Bug > Affects Versions: 7.0.0 > Reporter: Boris Kole > Assignee: Lukasz Lenart > Priority: Major > Fix For: 7.0.1 > > Time Spent: 10m > Remaining Estimate: 0h > > When using the debug Struts tag it throws the following errors. > |{*}Messages{*}:| # org.apache.struts2.text.DefaultTextProvider.texts > # Caught an exception while getting the property values of > org.apache.struts2.text.DefaultTextProvider@61995fff > # An exception occurred processing [/home.jsp] at line [3] 1: <%@ taglib > prefix="s" uri="/struts-tags" %> 2: 3: <s:debug/> Stacktrace:| > |{*}File{*}:|org/apache/jasper/servlet/JspServletWrapper.java| > |{*}Line number{*}:|599| > The JSP I used: > {code:java} > <%@ taglib prefix="s" uri="/struts-tags" %> > <s:debug/> {code} > -- This message was sent by Atlassian Jira (v8.20.10#820010)