Factor out template generation code into reusable class
This refactoring improves readability and lets us use the dynamic content part inside Google. For now, we have to pass in a converter to sanitize a string to be used in a script tag because our internal version of Soy does not support UnsafeSanitizedContentOrdainer. Remove SoyDataMap because it is marked as deprecated. Change-Id: I6d34708c98c6a4edae75defb6f45a0eab4c976bf
This commit is contained in:
135
java/com/google/gerrit/httpd/raw/IndexHtmlUtil.java
Normal file
135
java/com/google/gerrit/httpd/raw/IndexHtmlUtil.java
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
// Copyright (C) 2019 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// Licensed 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 com.google.gerrit.httpd.raw;
|
||||||
|
|
||||||
|
import static com.google.template.soy.data.ordainers.GsonOrdainer.serializeObject;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.flogger.FluentLogger;
|
||||||
|
import com.google.gerrit.common.Nullable;
|
||||||
|
import com.google.gerrit.common.UsedAt;
|
||||||
|
import com.google.gerrit.common.UsedAt.Project;
|
||||||
|
import com.google.gerrit.extensions.api.GerritApi;
|
||||||
|
import com.google.gerrit.extensions.api.accounts.AccountApi;
|
||||||
|
import com.google.gerrit.extensions.api.config.Server;
|
||||||
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
|
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||||
|
import com.google.gerrit.json.OutputFormat;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.template.soy.data.SanitizedContent;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/** Helper for generating parts of {@code index.html}. */
|
||||||
|
public class IndexHtmlUtil {
|
||||||
|
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns both static and dynamic parameters of {@code index.html}. The result is to be used when
|
||||||
|
* rendering the soy template.
|
||||||
|
*/
|
||||||
|
public static ImmutableMap<String, Object> templateData(
|
||||||
|
GerritApi gerritApi,
|
||||||
|
String canonicalURL,
|
||||||
|
String cdnPath,
|
||||||
|
String faviconPath,
|
||||||
|
Function<String, SanitizedContent> urlInScriptTagOrdainer)
|
||||||
|
throws URISyntaxException, RestApiException {
|
||||||
|
return ImmutableMap.<String, Object>builder()
|
||||||
|
.putAll(staticTemplateData(canonicalURL, cdnPath, faviconPath, urlInScriptTagOrdainer))
|
||||||
|
.putAll(dynamicTemplateData(gerritApi))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns dynamic parameters of {@code index.html}. */
|
||||||
|
@UsedAt(Project.GOOGLE)
|
||||||
|
public static Map<String, Map<String, SanitizedContent>> dynamicTemplateData(GerritApi gerritApi)
|
||||||
|
throws RestApiException {
|
||||||
|
Gson gson = OutputFormat.JSON_COMPACT.newGson();
|
||||||
|
Map<String, SanitizedContent> initialData = new HashMap<>();
|
||||||
|
Server serverApi = gerritApi.config().server();
|
||||||
|
initialData.put("\"/config/server/info\"", serializeObject(gson, serverApi.getInfo()));
|
||||||
|
initialData.put("\"/config/server/version\"", serializeObject(gson, serverApi.getVersion()));
|
||||||
|
initialData.put("\"/config/server/top-menus\"", serializeObject(gson, serverApi.topMenus()));
|
||||||
|
|
||||||
|
try {
|
||||||
|
AccountApi accountApi = gerritApi.accounts().self();
|
||||||
|
initialData.put("\"/accounts/self/detail\"", serializeObject(gson, accountApi.get()));
|
||||||
|
initialData.put(
|
||||||
|
"\"/accounts/self/preferences\"", serializeObject(gson, accountApi.getPreferences()));
|
||||||
|
initialData.put(
|
||||||
|
"\"/accounts/self/preferences.diff\"",
|
||||||
|
serializeObject(gson, accountApi.getDiffPreferences()));
|
||||||
|
initialData.put(
|
||||||
|
"\"/accounts/self/preferences.edit\"",
|
||||||
|
serializeObject(gson, accountApi.getEditPreferences()));
|
||||||
|
} catch (AuthException e) {
|
||||||
|
logger.atFine().withCause(e).log(
|
||||||
|
"Can't inline account-related data because user is unauthenticated");
|
||||||
|
// Don't render data
|
||||||
|
// TODO(hiesel): Tell the client that the user is not authenticated so that it doesn't have to
|
||||||
|
// fetch anyway. This requires more client side modifications.
|
||||||
|
}
|
||||||
|
return ImmutableMap.of("gerritInitialData", initialData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns all static parameters of {@code index.html}. */
|
||||||
|
static Map<String, Object> staticTemplateData(
|
||||||
|
String canonicalURL,
|
||||||
|
String cdnPath,
|
||||||
|
String faviconPath,
|
||||||
|
Function<String, SanitizedContent> urlInScriptTagOrdainer)
|
||||||
|
throws URISyntaxException {
|
||||||
|
String canonicalPath = computeCanonicalPath(canonicalURL);
|
||||||
|
|
||||||
|
String staticPath = "";
|
||||||
|
if (cdnPath != null) {
|
||||||
|
staticPath = cdnPath;
|
||||||
|
} else if (canonicalPath != null) {
|
||||||
|
staticPath = canonicalPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
SanitizedContent sanitizedStaticPath = urlInScriptTagOrdainer.apply(staticPath);
|
||||||
|
ImmutableMap.Builder<String, Object> data = ImmutableMap.builder();
|
||||||
|
if (canonicalPath != null) {
|
||||||
|
data.put("canonicalPath", canonicalPath);
|
||||||
|
}
|
||||||
|
if (sanitizedStaticPath != null) {
|
||||||
|
data.put("staticResourcePath", sanitizedStaticPath);
|
||||||
|
}
|
||||||
|
if (faviconPath != null) {
|
||||||
|
data.put("faviconPath", faviconPath);
|
||||||
|
}
|
||||||
|
return data.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String computeCanonicalPath(@Nullable String canonicalURL)
|
||||||
|
throws URISyntaxException {
|
||||||
|
if (Strings.isNullOrEmpty(canonicalURL)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we serving from a sub-directory rather than root, determine the path
|
||||||
|
// from the cannonical web URL.
|
||||||
|
URI uri = new URI(canonicalURL);
|
||||||
|
return uri.getPath().replaceAll("/$", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private IndexHtmlUtil() {}
|
||||||
|
}
|
@@ -14,38 +14,26 @@
|
|||||||
|
|
||||||
package com.google.gerrit.httpd.raw;
|
package com.google.gerrit.httpd.raw;
|
||||||
|
|
||||||
import static com.google.template.soy.data.ordainers.GsonOrdainer.serializeObject;
|
|
||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
|
||||||
import com.google.common.flogger.FluentLogger;
|
|
||||||
import com.google.common.io.Resources;
|
import com.google.common.io.Resources;
|
||||||
import com.google.gerrit.common.Nullable;
|
import com.google.gerrit.common.Nullable;
|
||||||
import com.google.gerrit.extensions.api.GerritApi;
|
import com.google.gerrit.extensions.api.GerritApi;
|
||||||
import com.google.gerrit.extensions.api.accounts.AccountApi;
|
|
||||||
import com.google.gerrit.extensions.api.config.Server;
|
|
||||||
import com.google.gerrit.extensions.restapi.AuthException;
|
|
||||||
import com.google.gerrit.extensions.restapi.RestApiException;
|
import com.google.gerrit.extensions.restapi.RestApiException;
|
||||||
import com.google.gerrit.json.OutputFormat;
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.template.soy.SoyFileSet;
|
import com.google.template.soy.SoyFileSet;
|
||||||
import com.google.template.soy.data.SanitizedContent;
|
import com.google.template.soy.data.SanitizedContent;
|
||||||
import com.google.template.soy.data.SoyMapData;
|
|
||||||
import com.google.template.soy.data.UnsafeSanitizedContentOrdainer;
|
import com.google.template.soy.data.UnsafeSanitizedContentOrdainer;
|
||||||
import com.google.template.soy.tofu.SoyTofu;
|
import com.google.template.soy.tofu.SoyTofu;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.util.HashMap;
|
import java.util.function.Function;
|
||||||
import java.util.Map;
|
|
||||||
import javax.servlet.http.HttpServlet;
|
import javax.servlet.http.HttpServlet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
public class IndexServlet extends HttpServlet {
|
public class IndexServlet extends HttpServlet {
|
||||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Nullable private final String canonicalUrl;
|
@Nullable private final String canonicalUrl;
|
||||||
@@ -53,6 +41,7 @@ public class IndexServlet extends HttpServlet {
|
|||||||
@Nullable private final String faviconPath;
|
@Nullable private final String faviconPath;
|
||||||
private final GerritApi gerritApi;
|
private final GerritApi gerritApi;
|
||||||
private final SoyTofu soyTofu;
|
private final SoyTofu soyTofu;
|
||||||
|
private final Function<String, SanitizedContent> urlOrdainer;
|
||||||
|
|
||||||
IndexServlet(
|
IndexServlet(
|
||||||
@Nullable String canonicalUrl,
|
@Nullable String canonicalUrl,
|
||||||
@@ -68,19 +57,24 @@ public class IndexServlet extends HttpServlet {
|
|||||||
.add(Resources.getResource("com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy"))
|
.add(Resources.getResource("com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy"))
|
||||||
.build()
|
.build()
|
||||||
.compileToTofu();
|
.compileToTofu();
|
||||||
|
this.urlOrdainer =
|
||||||
|
(s) ->
|
||||||
|
UnsafeSanitizedContentOrdainer.ordainAsSafe(
|
||||||
|
s, SanitizedContent.ContentKind.TRUSTED_RESOURCE_URI);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doGet(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
|
protected void doGet(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
|
||||||
SoyTofu.Renderer renderer;
|
SoyTofu.Renderer renderer;
|
||||||
try {
|
try {
|
||||||
SoyMapData templateData = getStaticTemplateData(canonicalUrl, cdnPath, faviconPath);
|
// TODO(hiesel): Remove URL ordainer as parameter once Soy is consistent
|
||||||
templateData.put("gerritInitialData", getInitialData());
|
|
||||||
renderer =
|
renderer =
|
||||||
soyTofu
|
soyTofu
|
||||||
.newRenderer("com.google.gerrit.httpd.raw.Index")
|
.newRenderer("com.google.gerrit.httpd.raw.Index")
|
||||||
.setContentKind(SanitizedContent.ContentKind.HTML)
|
.setContentKind(SanitizedContent.ContentKind.HTML)
|
||||||
.setData(templateData);
|
.setData(
|
||||||
|
IndexHtmlUtil.templateData(
|
||||||
|
gerritApi, canonicalUrl, cdnPath, faviconPath, urlOrdainer));
|
||||||
} catch (URISyntaxException | RestApiException e) {
|
} catch (URISyntaxException | RestApiException e) {
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
@@ -92,67 +86,4 @@ public class IndexServlet extends HttpServlet {
|
|||||||
w.write(renderer.render().getBytes(UTF_8));
|
w.write(renderer.render().getBytes(UTF_8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static String computeCanonicalPath(@Nullable String canonicalURL) throws URISyntaxException {
|
|
||||||
if (Strings.isNullOrEmpty(canonicalURL)) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we serving from a sub-directory rather than root, determine the path
|
|
||||||
// from the cannonical web URL.
|
|
||||||
URI uri = new URI(canonicalURL);
|
|
||||||
return uri.getPath().replaceAll("/$", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
static SoyMapData getStaticTemplateData(String canonicalURL, String cdnPath, String faviconPath)
|
|
||||||
throws URISyntaxException {
|
|
||||||
String canonicalPath = computeCanonicalPath(canonicalURL);
|
|
||||||
|
|
||||||
String staticPath = "";
|
|
||||||
if (cdnPath != null) {
|
|
||||||
staticPath = cdnPath;
|
|
||||||
} else if (canonicalPath != null) {
|
|
||||||
staticPath = canonicalPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The resource path must be typed as safe for use in a script src.
|
|
||||||
// TODO(wyatta): Upgrade this to use an appropriate safe URL type.
|
|
||||||
SanitizedContent sanitizedStaticPath =
|
|
||||||
UnsafeSanitizedContentOrdainer.ordainAsSafe(
|
|
||||||
staticPath, SanitizedContent.ContentKind.TRUSTED_RESOURCE_URI);
|
|
||||||
|
|
||||||
return new SoyMapData(
|
|
||||||
"canonicalPath", canonicalPath,
|
|
||||||
"staticResourcePath", sanitizedStaticPath,
|
|
||||||
"faviconPath", faviconPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, SanitizedContent> getInitialData() throws RestApiException {
|
|
||||||
Gson gson = OutputFormat.JSON_COMPACT.newGson();
|
|
||||||
Map<String, SanitizedContent> initialData = new HashMap<>();
|
|
||||||
Server serverApi = gerritApi.config().server();
|
|
||||||
initialData.put("\"/config/server/info\"", serializeObject(gson, serverApi.getInfo()));
|
|
||||||
initialData.put("\"/config/server/version\"", serializeObject(gson, serverApi.getVersion()));
|
|
||||||
initialData.put("\"/config/server/top-menus\"", serializeObject(gson, serverApi.topMenus()));
|
|
||||||
|
|
||||||
try {
|
|
||||||
AccountApi accountApi = gerritApi.accounts().self();
|
|
||||||
initialData.put("\"/accounts/self/detail\"", serializeObject(gson, accountApi.get()));
|
|
||||||
initialData.put(
|
|
||||||
"\"/accounts/self/preferences\"", serializeObject(gson, accountApi.getPreferences()));
|
|
||||||
initialData.put(
|
|
||||||
"\"/accounts/self/preferences.diff\"",
|
|
||||||
serializeObject(gson, accountApi.getDiffPreferences()));
|
|
||||||
initialData.put(
|
|
||||||
"\"/accounts/self/preferences.edit\"",
|
|
||||||
serializeObject(gson, accountApi.getEditPreferences()));
|
|
||||||
} catch (AuthException e) {
|
|
||||||
logger.atFine().withCause(e).log(
|
|
||||||
"Can't inline account-related data because user is unauthenticated");
|
|
||||||
// Don't render data
|
|
||||||
// TODO(hiesel): Tell the client that the user is not authenticated so that it doesn't have to
|
|
||||||
// fetch anyway. This requires more client side modifications.
|
|
||||||
}
|
|
||||||
return initialData;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
66
javatests/com/google/gerrit/httpd/raw/IndexHtmlUtilTest.java
Normal file
66
javatests/com/google/gerrit/httpd/raw/IndexHtmlUtilTest.java
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
// Copyright (C) 2019 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// Licensed 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 com.google.gerrit.httpd.raw;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static com.google.gerrit.httpd.raw.IndexHtmlUtil.staticTemplateData;
|
||||||
|
|
||||||
|
import com.google.template.soy.data.SanitizedContent;
|
||||||
|
import com.google.template.soy.data.UnsafeSanitizedContentOrdainer;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class IndexHtmlUtilTest {
|
||||||
|
@Test
|
||||||
|
public void noPathAndNoCDN() throws Exception {
|
||||||
|
assertThat(staticTemplateData("http://example.com/", null, null, IndexHtmlUtilTest::ordain))
|
||||||
|
.containsExactly("canonicalPath", "", "staticResourcePath", ordain(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void pathAndNoCDN() throws Exception {
|
||||||
|
assertThat(
|
||||||
|
staticTemplateData("http://example.com/gerrit/", null, null, IndexHtmlUtilTest::ordain))
|
||||||
|
.containsExactly("canonicalPath", "/gerrit", "staticResourcePath", ordain("/gerrit"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noPathAndCDN() throws Exception {
|
||||||
|
assertThat(
|
||||||
|
staticTemplateData(
|
||||||
|
"http://example.com/",
|
||||||
|
"http://my-cdn.com/foo/bar/",
|
||||||
|
null,
|
||||||
|
IndexHtmlUtilTest::ordain))
|
||||||
|
.containsExactly(
|
||||||
|
"canonicalPath", "", "staticResourcePath", ordain("http://my-cdn.com/foo/bar/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void pathAndCDN() throws Exception {
|
||||||
|
assertThat(
|
||||||
|
staticTemplateData(
|
||||||
|
"http://example.com/gerrit",
|
||||||
|
"http://my-cdn.com/foo/bar/",
|
||||||
|
null,
|
||||||
|
IndexHtmlUtilTest::ordain))
|
||||||
|
.containsExactly(
|
||||||
|
"canonicalPath", "/gerrit", "staticResourcePath", ordain("http://my-cdn.com/foo/bar/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SanitizedContent ordain(String s) {
|
||||||
|
return UnsafeSanitizedContentOrdainer.ordainAsSafe(
|
||||||
|
s, SanitizedContent.ContentKind.TRUSTED_RESOURCE_URI);
|
||||||
|
}
|
||||||
|
}
|
@@ -29,43 +29,9 @@ import com.google.gerrit.extensions.common.ServerInfo;
|
|||||||
import com.google.gerrit.extensions.restapi.AuthException;
|
import com.google.gerrit.extensions.restapi.AuthException;
|
||||||
import com.google.gerrit.util.http.testutil.FakeHttpServletRequest;
|
import com.google.gerrit.util.http.testutil.FakeHttpServletRequest;
|
||||||
import com.google.gerrit.util.http.testutil.FakeHttpServletResponse;
|
import com.google.gerrit.util.http.testutil.FakeHttpServletResponse;
|
||||||
import com.google.template.soy.data.SoyMapData;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class IndexServletTest {
|
public class IndexServletTest {
|
||||||
@Test
|
|
||||||
public void noPathAndNoCDN() throws Exception {
|
|
||||||
SoyMapData data = IndexServlet.getStaticTemplateData("http://example.com/", null, null);
|
|
||||||
assertThat(data.getSingle("canonicalPath").stringValue()).isEqualTo("");
|
|
||||||
assertThat(data.getSingle("staticResourcePath").stringValue()).isEqualTo("");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void pathAndNoCDN() throws Exception {
|
|
||||||
SoyMapData data = IndexServlet.getStaticTemplateData("http://example.com/gerrit/", null, null);
|
|
||||||
assertThat(data.getSingle("canonicalPath").stringValue()).isEqualTo("/gerrit");
|
|
||||||
assertThat(data.getSingle("staticResourcePath").stringValue()).isEqualTo("/gerrit");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void noPathAndCDN() throws Exception {
|
|
||||||
SoyMapData data =
|
|
||||||
IndexServlet.getStaticTemplateData(
|
|
||||||
"http://example.com/", "http://my-cdn.com/foo/bar/", null);
|
|
||||||
assertThat(data.getSingle("canonicalPath").stringValue()).isEqualTo("");
|
|
||||||
assertThat(data.getSingle("staticResourcePath").stringValue())
|
|
||||||
.isEqualTo("http://my-cdn.com/foo/bar/");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void pathAndCDN() throws Exception {
|
|
||||||
SoyMapData data =
|
|
||||||
IndexServlet.getStaticTemplateData(
|
|
||||||
"http://example.com/gerrit", "http://my-cdn.com/foo/bar/", null);
|
|
||||||
assertThat(data.getSingle("canonicalPath").stringValue()).isEqualTo("/gerrit");
|
|
||||||
assertThat(data.getSingle("staticResourcePath").stringValue())
|
|
||||||
.isEqualTo("http://my-cdn.com/foo/bar/");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void renderTemplate() throws Exception {
|
public void renderTemplate() throws Exception {
|
||||||
|
Reference in New Issue
Block a user