You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CvalCheckerTest.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. package com.vaadin.tools;
  2. import static com.vaadin.tools.CvalAddonsChecker.VAADIN_ADDON_LICENSE;
  3. import static com.vaadin.tools.CvalAddonsChecker.VAADIN_ADDON_NAME;
  4. import static com.vaadin.tools.CvalAddonsChecker.VAADIN_ADDON_TITLE;
  5. import static com.vaadin.tools.CvalAddonsChecker.VAADIN_ADDON_VERSION;
  6. import static com.vaadin.tools.CvalChecker.GRACE_DAYS_MSECS;
  7. import static com.vaadin.tools.CvalChecker.cacheLicenseInfo;
  8. import static com.vaadin.tools.CvalChecker.deleteCache;
  9. import static com.vaadin.tools.CvalChecker.parseJson;
  10. import static org.junit.Assert.assertEquals;
  11. import static org.junit.Assert.assertNull;
  12. import static org.junit.Assert.assertTrue;
  13. import java.io.ByteArrayOutputStream;
  14. import java.io.File;
  15. import java.io.FileDescriptor;
  16. import java.io.FileNotFoundException;
  17. import java.io.FileOutputStream;
  18. import java.io.IOException;
  19. import java.io.PrintStream;
  20. import java.io.PrintWriter;
  21. import java.lang.reflect.Method;
  22. import java.net.URL;
  23. import java.net.URLClassLoader;
  24. import java.util.jar.JarOutputStream;
  25. import java.util.jar.Manifest;
  26. import java.util.prefs.Preferences;
  27. import org.junit.Assert;
  28. import org.junit.Before;
  29. import org.junit.Test;
  30. import com.vaadin.tools.CvalChecker.CvalInfo;
  31. import com.vaadin.tools.CvalChecker.CvalServer;
  32. import com.vaadin.tools.CvalChecker.InvalidCvalException;
  33. import com.vaadin.tools.CvalChecker.UnreachableCvalServerException;
  34. /**
  35. * The CvalChecker test.
  36. */
  37. public class CvalCheckerTest {
  38. static final String productNameCval = "test.cval";
  39. static final String productTitleCval = "Vaadin Test";
  40. static final String productNameAgpl = "test.agpl";
  41. static final String productTitleAgpl = "Vaadin Test";
  42. static final String productNameApache = "test.apache";
  43. static final String VALID_KEY = "valid";
  44. static final String INVALID_KEY = "invalid";
  45. static final String responseJson = "{'licenseKey':'" + VALID_KEY + "',"
  46. + "'licensee':'Test User','type':'normal',"
  47. + "'expiredEpoch':1893511225000," + "'product':{'name':'"
  48. + productNameCval + "', 'version': 2}}";
  49. static final String responseJsonWithNullVersion = "{'licenseKey':'"
  50. + VALID_KEY + "'," + "'licensee':'Test User','type':'normal',"
  51. + "'expiredEpoch':1893511225000," + "'product':{'name':'"
  52. + productNameCval + "', 'version': null}}";
  53. private static ByteArrayOutputStream outContent;
  54. // A provider returning a valid license if productKey is valid or null if
  55. // invalid
  56. static final CvalServer validLicenseProvider = new CvalServer() {
  57. @Override
  58. String askServer(String productName, String productKey, int timeout) {
  59. return VALID_KEY.equals(productKey) ? responseJson : null;
  60. }
  61. };
  62. // A provider returning a valid evaluation license
  63. static final CvalServer validEvaluationLicenseProvider = new CvalServer() {
  64. @Override
  65. String askServer(String productName, String productKey, int timeout) {
  66. return responseJson.replace("normal", "evaluation");
  67. }
  68. };
  69. // A provider returning an expired license with a server message
  70. static final CvalServer expiredLicenseProviderWithMessage = new CvalServer() {
  71. @Override
  72. String askServer(String productName, String productKey, int timeout) {
  73. return responseJson.replace("'expired",
  74. "'message':'Custom\\\\nServer\\\\nMessage','expired':true,'expired");
  75. }
  76. };
  77. // A provider returning an expired license with a server message
  78. static final CvalServer expiredLicenseProvider = new CvalServer() {
  79. @Override
  80. String askServer(String productName, String productKey, int timeout) {
  81. return responseJson.replace("'expired", "'expired':true,'expired");
  82. }
  83. };
  84. // A provider returning an expired epoch license
  85. static final CvalServer expiredEpochLicenseProvider = new CvalServer() {
  86. @Override
  87. String askServer(String productName, String productKey, int timeout) {
  88. long ts = System.currentTimeMillis() - GRACE_DAYS_MSECS - 1000;
  89. return responseJson.replace("1893511225000", "" + ts);
  90. }
  91. };
  92. // A provider returning an unlimited license
  93. static final CvalServer unlimitedLicenseProvider = new CvalServer() {
  94. @Override
  95. String askServer(String productName, String productKey, int timeout) {
  96. return responseJson.replaceFirst("1893511225000", "null");
  97. }
  98. };
  99. // An unreachable provider
  100. static final CvalServer unreachableLicenseProvider = new CvalServer() {
  101. @Override
  102. String askServer(String productName, String productKey, int timeout)
  103. throws IOException {
  104. // Normally there is no route for this ip in public routers, so we
  105. // should get a timeout.
  106. licenseUrl = "http://localhost:9999/";
  107. return super.askServer(productName, productKey, 1000);
  108. }
  109. };
  110. // A provider with 'null' in the version field
  111. static final CvalServer nullVersionLicenseProvider = new CvalServer() {
  112. @Override
  113. String askServer(String productName, String productKey, int timeout)
  114. throws IOException {
  115. return responseJsonWithNullVersion;
  116. }
  117. };
  118. private CvalChecker licenseChecker;
  119. private String licenseName;
  120. @Before
  121. public void setup() {
  122. licenseChecker = new CvalChecker()
  123. .setLicenseProvider(validLicenseProvider);
  124. licenseName = CvalChecker.computeLicenseName(productNameCval);
  125. System.getProperties().remove(licenseName);
  126. deleteCache(productNameCval);
  127. }
  128. @Test
  129. public void testValidateProduct() throws Exception {
  130. deleteCache(productNameCval);
  131. // If the license key in our environment is null, throw an exception
  132. try {
  133. licenseChecker.validateProduct(productNameCval, "2.1",
  134. productTitleCval);
  135. Assert.fail();
  136. } catch (InvalidCvalException expected) {
  137. assertEquals(productNameCval, expected.name);
  138. }
  139. Assert.assertFalse(cacheExists(productNameCval));
  140. // If the license key is empty, throw an exception
  141. System.setProperty(licenseName, "");
  142. try {
  143. licenseChecker.validateProduct(productNameCval, "2.1",
  144. productTitleCval);
  145. Assert.fail();
  146. } catch (InvalidCvalException expected) {
  147. assertEquals(productNameCval, expected.name);
  148. }
  149. Assert.assertFalse(cacheExists(productNameCval));
  150. // If license key is invalid, throw an exception
  151. System.setProperty(licenseName, "invalid");
  152. try {
  153. licenseChecker.validateProduct(productNameCval, "2.1",
  154. productTitleCval);
  155. Assert.fail();
  156. } catch (InvalidCvalException expected) {
  157. assertEquals(productNameCval, expected.name);
  158. }
  159. Assert.assertFalse(cacheExists(productNameCval));
  160. // Fail if version is bigger
  161. System.setProperty(licenseName, VALID_KEY);
  162. try {
  163. licenseChecker.validateProduct(productNameCval, "3.0",
  164. productTitleCval);
  165. Assert.fail();
  166. } catch (InvalidCvalException expected) {
  167. assertEquals(productNameCval, expected.name);
  168. assertTrue(expected.getMessage().contains("is not valid"));
  169. }
  170. Assert.assertFalse(cacheExists(productNameCval));
  171. // Success if license key and version are valid
  172. System.setProperty(licenseName, VALID_KEY);
  173. licenseChecker.validateProduct(productNameCval, "2.1",
  174. productTitleCval);
  175. Assert.assertTrue(cacheExists(productNameCval));
  176. // Success if license and cache file are valid, although the license
  177. // server is offline
  178. licenseChecker.setLicenseProvider(unreachableLicenseProvider);
  179. licenseChecker.validateProduct(productNameCval, "2.1",
  180. productTitleCval);
  181. Assert.assertTrue(cacheExists(productNameCval));
  182. // Fail if license key changes although cache file were validated
  183. // previously and it is ok, we are offline
  184. try {
  185. System.setProperty(licenseName, INVALID_KEY);
  186. licenseChecker.validateProduct(productNameCval, "2.1",
  187. productTitleCval);
  188. Assert.fail();
  189. } catch (InvalidCvalException expected) {
  190. Assert.fail();
  191. } catch (UnreachableCvalServerException expected) {
  192. assertEquals(productNameCval, expected.name);
  193. }
  194. Assert.assertFalse(cacheExists(productNameCval));
  195. // Fail with unreachable exception if license has never verified and
  196. // server is offline
  197. try {
  198. System.setProperty(licenseName, VALID_KEY);
  199. licenseChecker.validateProduct(productNameCval, "2.1",
  200. productTitleCval);
  201. Assert.fail();
  202. } catch (InvalidCvalException expected) {
  203. Assert.fail();
  204. } catch (UnreachableCvalServerException expected) {
  205. assertEquals(productNameCval, expected.name);
  206. }
  207. Assert.assertFalse(cacheExists(productNameCval));
  208. // Fail when expired flag comes in the server response, although the
  209. // expired is valid.
  210. deleteCache(productNameCval);
  211. licenseChecker.setLicenseProvider(expiredLicenseProviderWithMessage);
  212. try {
  213. licenseChecker.validateProduct(productNameCval, "2.1",
  214. productTitleCval);
  215. Assert.fail();
  216. } catch (InvalidCvalException expected) {
  217. assertEquals(productNameCval, expected.name);
  218. // Check that we use server customized message if it comes
  219. Assert.assertTrue(expected.getMessage().contains("Custom"));
  220. }
  221. Assert.assertTrue(cacheExists(productNameCval));
  222. // Check an unlimited license
  223. deleteCache(productNameCval);
  224. licenseChecker.setLicenseProvider(unlimitedLicenseProvider);
  225. licenseChecker.validateProduct(productNameCval, "2.1",
  226. productTitleCval);
  227. Assert.assertTrue(cacheExists(productNameCval));
  228. // Fail if expired flag does not come, but expired epoch is in the past
  229. System.setProperty(licenseName, VALID_KEY);
  230. deleteCache(productNameCval);
  231. licenseChecker.setLicenseProvider(expiredEpochLicenseProvider);
  232. try {
  233. licenseChecker.validateProduct(productNameCval, "2.1",
  234. productTitleCval);
  235. Assert.fail();
  236. } catch (InvalidCvalException expected) {
  237. assertEquals(productNameCval, expected.name);
  238. }
  239. Assert.assertTrue(cacheExists(productNameCval));
  240. deleteCache(productNameCval);
  241. licenseChecker.setLicenseProvider(nullVersionLicenseProvider);
  242. licenseChecker.validateProduct(productNameCval, "2.1",
  243. productTitleCval);
  244. Assert.assertTrue(cacheExists(productNameCval));
  245. }
  246. /*
  247. * Creates a new .jar file with a MANIFEST.MF with all vaadin license info
  248. * attributes set, and add the .jar to the classpath
  249. */
  250. static void addLicensedJarToClasspath(String productName,
  251. String licenseType) throws Exception {
  252. // Create a manifest with Vaadin CVAL license
  253. Manifest testManifest = new Manifest();
  254. testManifest.getMainAttributes().putValue("Manifest-Version", "1.0");
  255. testManifest.getMainAttributes().putValue(VAADIN_ADDON_LICENSE,
  256. licenseType);
  257. testManifest.getMainAttributes().putValue(VAADIN_ADDON_NAME,
  258. productName);
  259. testManifest.getMainAttributes().putValue(VAADIN_ADDON_TITLE,
  260. "Test " + productName);
  261. testManifest.getMainAttributes().putValue(VAADIN_ADDON_VERSION, "2");
  262. // Create a temporary Jar
  263. File testJarFile = File.createTempFile("vaadin." + productName, ".jar");
  264. testJarFile.deleteOnExit();
  265. JarOutputStream target = new JarOutputStream(
  266. new FileOutputStream(testJarFile), testManifest);
  267. target.close();
  268. // Add the new jar to our classpath (use reflection)
  269. URL url = testJarFile.toURI().toURL();
  270. final Method addURL = URLClassLoader.class.getDeclaredMethod("addURL",
  271. new Class[] { URL.class });
  272. addURL.setAccessible(true);
  273. final URLClassLoader urlClassLoader = (URLClassLoader) Thread
  274. .currentThread().getContextClassLoader();
  275. addURL.invoke(urlClassLoader, new Object[] { url });
  276. }
  277. static boolean cacheExists(String productName) {
  278. return cachedPreferences(productName) != null;
  279. }
  280. static String cachedPreferences(String productName) {
  281. // ~/Library/Preferences/com.apple.java.util.prefs.plist
  282. // .java/.userPrefs/com/google/gwt/dev/shell/prefs.xml
  283. // HKEY_CURRENT_USER\SOFTWARE\JavaSoft\Prefs
  284. Preferences p = Preferences.userNodeForPackage(CvalInfo.class);
  285. return p.get(productName, null);
  286. }
  287. static void saveCache(String productName, String key, Boolean expired,
  288. Long expireTs, String type) {
  289. String json = responseJson.replace(productNameCval, productName);
  290. if (expired != null && expired) {
  291. expireTs = System.currentTimeMillis() - GRACE_DAYS_MSECS - 1000;
  292. }
  293. if (expireTs != null) {
  294. json = json.replace("1893511225000", "" + expireTs);
  295. }
  296. if (key != null) {
  297. json = json.replace(VALID_KEY, key);
  298. }
  299. if (type != null) {
  300. json = json.replace("normal", type);
  301. }
  302. cacheLicenseInfo(parseJson(json));
  303. }
  304. static void captureSystemOut() {
  305. outContent = new ByteArrayOutputStream();
  306. System.setOut(new PrintStream(outContent));
  307. }
  308. static String readSystemOut() {
  309. restoreSystemOut();
  310. return outContent.toString();
  311. }
  312. static void restoreSystemOut() {
  313. System.setOut(
  314. new PrintStream(new FileOutputStream(FileDescriptor.out)));
  315. }
  316. @Test(expected = FileNotFoundException.class)
  317. public void testReadKeyFromFile_NonexistingLicenseFile() throws Exception {
  318. licenseChecker.readKeyFromFile(new URL("file:///foobar.baz"), 4);
  319. }
  320. @Test
  321. public void testReadKeyFromFile_LicenseFileEmpty() throws Exception {
  322. File tmpLicenseFile = File.createTempFile("license", "lic");
  323. assertNull(licenseChecker
  324. .readKeyFromFile(tmpLicenseFile.toURI().toURL(), 4));
  325. tmpLicenseFile.delete();
  326. }
  327. @Test
  328. public void testReadKeyFromFile_LicenseFileHasSingleUnidentifiedKey()
  329. throws Exception {
  330. File tmpLicenseFile = File.createTempFile("license", "lic");
  331. PrintWriter out = new PrintWriter(tmpLicenseFile);
  332. out.println("this-is-a-license");
  333. out.close();
  334. assertEquals("this-is-a-license", licenseChecker
  335. .readKeyFromFile(tmpLicenseFile.toURI().toURL(), 4));
  336. tmpLicenseFile.delete();
  337. }
  338. @Test
  339. public void testReadKeyFromFile_LicenseFileHasSingleIdentifiedKey()
  340. throws Exception {
  341. File tmpLicenseFile = File.createTempFile("license", "lic");
  342. PrintWriter out = new PrintWriter(tmpLicenseFile);
  343. out.println("4=this-is-a-license");
  344. out.close();
  345. assertEquals("this-is-a-license", licenseChecker
  346. .readKeyFromFile(tmpLicenseFile.toURI().toURL(), 4));
  347. tmpLicenseFile.delete();
  348. }
  349. @Test
  350. public void testReadKeyFromFile_LicenseFileHasMultipleKeys()
  351. throws Exception {
  352. File tmpLicenseFile = File.createTempFile("license", "lic");
  353. PrintWriter out = new PrintWriter(tmpLicenseFile);
  354. out.println("4=this-is-a-license");
  355. out.println("5=this-is-another-license");
  356. out.close();
  357. assertEquals("this-is-a-license", licenseChecker
  358. .readKeyFromFile(tmpLicenseFile.toURI().toURL(), 4));
  359. assertEquals("this-is-another-license", licenseChecker
  360. .readKeyFromFile(tmpLicenseFile.toURI().toURL(), 5));
  361. tmpLicenseFile.delete();
  362. }
  363. @Test
  364. public void testReadKeyFromFile_LicenseFileHasMultipleKeysWithWhitespace()
  365. throws Exception {
  366. File tmpLicenseFile = File.createTempFile("license", "lic");
  367. PrintWriter out = new PrintWriter(tmpLicenseFile);
  368. out.println("4 = this-is-a-license");
  369. out.println("5 = this-is-another-license");
  370. out.close();
  371. assertEquals("this-is-a-license", licenseChecker
  372. .readKeyFromFile(tmpLicenseFile.toURI().toURL(), 4));
  373. assertEquals("this-is-another-license", licenseChecker
  374. .readKeyFromFile(tmpLicenseFile.toURI().toURL(), 5));
  375. tmpLicenseFile.delete();
  376. }
  377. @Test
  378. public void testReadKeyFromFile_RequestedVersionMissing() throws Exception {
  379. File tmpLicenseFile = File.createTempFile("license", "lic");
  380. PrintWriter out = new PrintWriter(tmpLicenseFile);
  381. out.println("4 = this-is-a-license");
  382. out.println("5 = this-is-another-license");
  383. out.close();
  384. assertNull(licenseChecker
  385. .readKeyFromFile(tmpLicenseFile.toURI().toURL(), 3));
  386. tmpLicenseFile.delete();
  387. }
  388. @Test
  389. public void testReadKeyFromFile_FallbackToDefaultKey() throws Exception {
  390. File tmpLicenseFile = File.createTempFile("license", "lic");
  391. PrintWriter out = new PrintWriter(tmpLicenseFile);
  392. out.println("this-is-a-license");
  393. out.println("5 = this-is-another-license");
  394. out.close();
  395. assertEquals("this-is-a-license", licenseChecker
  396. .readKeyFromFile(tmpLicenseFile.toURI().toURL(), 3));
  397. assertEquals("this-is-a-license", licenseChecker
  398. .readKeyFromFile(tmpLicenseFile.toURI().toURL(), 4));
  399. assertEquals("this-is-another-license", licenseChecker
  400. .readKeyFromFile(tmpLicenseFile.toURI().toURL(), 5));
  401. tmpLicenseFile.delete();
  402. }
  403. @Test
  404. public void testReadKeyFromFile_FallbackToDefaultKeyReversed()
  405. throws Exception {
  406. File tmpLicenseFile = File.createTempFile("license", "lic");
  407. PrintWriter out = new PrintWriter(tmpLicenseFile);
  408. out.println("5 = this-is-another-license");
  409. out.println("this-is-a-license");
  410. out.close();
  411. assertEquals("this-is-a-license", licenseChecker
  412. .readKeyFromFile(tmpLicenseFile.toURI().toURL(), 3));
  413. assertEquals("this-is-a-license", licenseChecker
  414. .readKeyFromFile(tmpLicenseFile.toURI().toURL(), 4));
  415. assertEquals("this-is-another-license", licenseChecker
  416. .readKeyFromFile(tmpLicenseFile.toURI().toURL(), 5));
  417. tmpLicenseFile.delete();
  418. }
  419. }