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

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