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

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