View Javadoc
1   /**
2    * SpamSchutz - simple way to protect your mail addresses from naïve spammers
3    * Copyright (C) 2011, Aiki IT
4    * <p>
5    * This program is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    * <p>
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   * <p>
15   * You should have received a copy of the GNU General Public License
16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  package de.aikiit.spamprotector;
19  
20  import de.aikiit.spamprotector.converter.SpamProtector;
21  import de.aikiit.spamprotector.util.LocalizationHelper;
22  import org.junit.Test;
23  
24  import java.io.File;
25  import java.nio.file.Files;
26  import java.nio.file.Path;
27  import java.util.Locale;
28  import java.util.concurrent.TimeUnit;
29  import java.util.jar.JarFile;
30  
31  import static org.assertj.core.api.Assertions.assertThat;
32  
33  /**
34   * Regression coverage for the executable JAR used by Java and jBang (#94).
35   */
36  public class ExecutableJarIT {
37  
38      @Test
39      public void packagedApplicationIncludesServicesAndResources() throws Exception {
40          Path jar = Path.of(System.getProperty("executableJar")).toAbsolutePath();
41          try (JarFile archive = new JarFile(jar.toFile())) {
42              assertThat(archive.getManifest().getMainAttributes().getValue("Main-Class"))
43                      .isEqualTo(AntiSpamApplication.class.getName());
44          }
45  
46          String java = Path.of(System.getProperty("java.home"), "bin",
47                  System.getProperty("os.name").startsWith("Windows") ? "java.exe" : "java").toString();
48          String classpath = jar + File.pathSeparator + System.getProperty("testClasses");
49          Path log = Files.createTempFile("spamschutz-executable-", ".log");
50          Process process = null;
51          try {
52              // Deliberately exclude Maven's dependency classpath: everything must come from the JAR.
53              process = new ProcessBuilder(java, "-Djava.awt.headless=true", "-cp", classpath,
54                      Probe.class.getName()).redirectErrorStream(true).redirectOutput(log.toFile()).start();
55              assertThat(process.waitFor(30, TimeUnit.SECONDS))
56                      .as("Executable JAR smoke test completed within 30 seconds")
57                      .isTrue();
58              String output = Files.readString(log);
59              assertThat(process.exitValue()).as("Process output: %s", output).isZero();
60              assertThat(output).contains("Executable JAR smoke test passed");
61          } finally {
62              if (process != null && process.isAlive()) {
63                  process.destroyForcibly().waitFor();
64              }
65              Files.deleteIfExists(log);
66          }
67      }
68  
69      /**
70       * Standalone probe, also runnable through the jBang catalog without opening a GUI.
71       * Does not use JUnit or AssertJ, which are intentionally absent from the child JVM's classpath.
72       */
73      public static final class Probe {
74  
75          public static void main(String[] args) throws Exception {
76              // Reflection avoids inlining the generated constant and verifies the class is packaged.
77              String version = (String) Class.forName("de.aikiit.spamprotector.util.Version")
78                      .getField("VERSION").get(null);
79              if (version.isEmpty() || version.contains("${")) {
80                  throw new IllegalStateException("Missing Maven-filtered version: " + version);
81              }
82              for (String language : new String[]{"de", "en"}) {
83                  // Match a JVM started in this locale; ResourceBundle also uses the JVM default
84                  // when falling back to the German root bundle on English CI hosts.
85                  Locale.setDefault("de".equals(language) ? Locale.GERMANY : Locale.US);
86                  System.setProperty("user.language", language);
87                  System.setProperty("user.country", "de".equals(language) ? "DE" : "US");
88                  // Initializes Log4j as well as the packaged localization resources.
89                  LocalizationHelper.setLocale();
90                  String title = LocalizationHelper.getBundleString("spamschutz.main.title");
91                  String expected = "de".equals(language) ? "SpamSchutz" : "SpamProtector";
92                  if (!title.startsWith(expected)) {
93                      throw new IllegalStateException("Missing localization for " + language + ": " + title);
94                  }
95              }
96              String input = "hello@example.org";
97              if (!input.equals(SpamProtector.toPlain(SpamProtector.toEncoded(input)))) {
98                  throw new IllegalStateException("Conversion roundtrip failed");
99              }
100             System.out.println("Executable JAR smoke test passed: " + version);
101         }
102     }
103 }