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

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