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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /*
  2. * Copyright 2000-2014 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 java.io.ByteArrayOutputStream;
  28. import java.io.File;
  29. import java.io.FileDescriptor;
  30. import java.io.FileNotFoundException;
  31. import java.io.FileOutputStream;
  32. import java.io.IOException;
  33. import java.io.PrintStream;
  34. import java.io.PrintWriter;
  35. import java.lang.reflect.Method;
  36. import java.net.URL;
  37. import java.net.URLClassLoader;
  38. import java.util.jar.JarOutputStream;
  39. import java.util.jar.Manifest;
  40. import java.util.prefs.Preferences;
  41. import org.junit.Assert;
  42. import org.junit.Before;
  43. import org.junit.Test;
  44. import com.vaadin.tools.CvalChecker.CvalInfo;
  45. import com.vaadin.tools.CvalChecker.CvalServer;
  46. import com.vaadin.tools.CvalChecker.InvalidCvalException;
  47. import com.vaadin.tools.CvalChecker.UnreachableCvalServerException;
  48. /**
  49. * The CvalChecker test.
  50. */
  51. public class CvalCheckerTest {
  52. static final String productNameCval = "test.cval";
  53. static final String productTitleCval = "Vaadin Test";
  54. static final String productNameAgpl = "test.agpl";
  55. static final String productTitleAgpl = "Vaadin Test";
  56. static final String productNameApache = "test.apache";
  57. static final String VALID_KEY = "valid";
  58. static final String INVALID_KEY = "invalid";
  59. static final String responseJson = "{'licenseKey':'" + VALID_KEY + "',"
  60. + "'licensee':'Test User','type':'normal',"
  61. + "'expiredEpoch':1893511225000," + "'product':{'name':'"
  62. + productNameCval + "', 'version': 2}}";
  63. static final String responseJsonWithNullVersion = "{'licenseKey':'" + VALID_KEY + "',"
  64. + "'licensee':'Test User','type':'normal',"
  65. + "'expiredEpoch':1893511225000," + "'product':{'name':'"
  66. + productNameCval + "', 'version': null}}";
  67. private static ByteArrayOutputStream outContent;
  68. // A provider returning a valid license if productKey is valid or null if
  69. // invalid
  70. static final CvalServer validLicenseProvider = new CvalServer() {
  71. @Override
  72. String askServer(String productName, String productKey, int timeout) {
  73. return VALID_KEY.equals(productKey) ? responseJson : null;
  74. }
  75. };
  76. // A provider returning a valid evaluation license
  77. static final CvalServer validEvaluationLicenseProvider = new CvalServer() {
  78. @Override
  79. String askServer(String productName, String productKey, int timeout) {
  80. return responseJson.replace("normal", "evaluation");
  81. }
  82. };
  83. // A provider returning an expired license with a server message
  84. static final CvalServer expiredLicenseProviderWithMessage = new CvalServer() {
  85. @Override
  86. String askServer(String productName, String productKey, int timeout) {
  87. return responseJson
  88. .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. }
  184. Assert.assertFalse(cacheExists(productNameCval));
  185. // Success if license key and version are valid
  186. System.setProperty(licenseName, VALID_KEY);
  187. licenseChecker
  188. .validateProduct(productNameCval, "2.1", productTitleCval);
  189. Assert.assertTrue(cacheExists(productNameCval));
  190. // Success if license and cache file are valid, although the license
  191. // server is offline
  192. licenseChecker.setLicenseProvider(unreachableLicenseProvider);
  193. licenseChecker
  194. .validateProduct(productNameCval, "2.1", productTitleCval);
  195. Assert.assertTrue(cacheExists(productNameCval));
  196. // Fail if license key changes although cache file were validated
  197. // previously and it is ok, we are offline
  198. try {
  199. System.setProperty(licenseName, INVALID_KEY);
  200. licenseChecker.validateProduct(productNameCval, "2.1",
  201. productTitleCval);
  202. Assert.fail();
  203. } catch (InvalidCvalException expected) {
  204. Assert.fail();
  205. } catch (UnreachableCvalServerException expected) {
  206. assertEquals(productNameCval, expected.name);
  207. }
  208. Assert.assertFalse(cacheExists(productNameCval));
  209. // Fail with unreachable exception if license has never verified and
  210. // server is offline
  211. try {
  212. System.setProperty(licenseName, VALID_KEY);
  213. licenseChecker.validateProduct(productNameCval, "2.1",
  214. productTitleCval);
  215. Assert.fail();
  216. } catch (InvalidCvalException expected) {
  217. Assert.fail();
  218. } catch (UnreachableCvalServerException expected) {
  219. assertEquals(productNameCval, expected.name);
  220. }
  221. Assert.assertFalse(cacheExists(productNameCval));
  222. // Fail when expired flag comes in the server response, although the
  223. // expired is valid.
  224. deleteCache(productNameCval);
  225. licenseChecker.setLicenseProvider(expiredLicenseProviderWithMessage);
  226. try {
  227. licenseChecker.validateProduct(productNameCval, "2.1",
  228. productTitleCval);
  229. Assert.fail();
  230. } catch (InvalidCvalException expected) {
  231. assertEquals(productNameCval, expected.name);
  232. // Check that we use server customized message if it comes
  233. Assert.assertTrue(expected.getMessage().contains("Custom"));
  234. }
  235. Assert.assertTrue(cacheExists(productNameCval));
  236. // Check an unlimited license
  237. deleteCache(productNameCval);
  238. licenseChecker.setLicenseProvider(unlimitedLicenseProvider);
  239. licenseChecker
  240. .validateProduct(productNameCval, "2.1", productTitleCval);
  241. Assert.assertTrue(cacheExists(productNameCval));
  242. // Fail if expired flag does not come, but expired epoch is in the past
  243. System.setProperty(licenseName, VALID_KEY);
  244. deleteCache(productNameCval);
  245. licenseChecker.setLicenseProvider(expiredEpochLicenseProvider);
  246. try {
  247. licenseChecker.validateProduct(productNameCval, "2.1",
  248. productTitleCval);
  249. Assert.fail();
  250. } catch (InvalidCvalException expected) {
  251. assertEquals(productNameCval, expected.name);
  252. }
  253. Assert.assertTrue(cacheExists(productNameCval));
  254. deleteCache(productNameCval);
  255. licenseChecker.setLicenseProvider(nullVersionLicenseProvider);
  256. licenseChecker
  257. .validateProduct(productNameCval, "2.1", productTitleCval);
  258. Assert.assertTrue(cacheExists(productNameCval));
  259. }
  260. /*
  261. * Creates a new .jar file with a MANIFEST.MF with all vaadin license info
  262. * attributes set, and add the .jar to the classpath
  263. */
  264. static void addLicensedJarToClasspath(String productName, String licenseType)
  265. throws Exception {
  266. // Create a manifest with Vaadin CVAL license
  267. Manifest testManifest = new Manifest();
  268. testManifest.getMainAttributes().putValue("Manifest-Version", "1.0");
  269. testManifest.getMainAttributes().putValue(VAADIN_ADDON_LICENSE,
  270. licenseType);
  271. testManifest.getMainAttributes().putValue(VAADIN_ADDON_NAME,
  272. productName);
  273. testManifest.getMainAttributes().putValue(VAADIN_ADDON_TITLE,
  274. "Test " + productName);
  275. testManifest.getMainAttributes().putValue(VAADIN_ADDON_VERSION, "2");
  276. // Create a temporary Jar
  277. File testJarFile = File.createTempFile("vaadin." + productName, "jar");
  278. testJarFile.deleteOnExit();
  279. JarOutputStream target = new JarOutputStream(new FileOutputStream(
  280. testJarFile), testManifest);
  281. target.close();
  282. // Add the new jar to our classpath (use reflection)
  283. URL url = new URL("file://" + testJarFile.getAbsolutePath());
  284. final Method addURL = URLClassLoader.class.getDeclaredMethod("addURL",
  285. new Class[] { URL.class });
  286. addURL.setAccessible(true);
  287. final URLClassLoader urlClassLoader = (URLClassLoader) Thread
  288. .currentThread().getContextClassLoader();
  289. addURL.invoke(urlClassLoader, new Object[] { url });
  290. }
  291. static boolean cacheExists(String productName) {
  292. return cachedPreferences(productName) != null;
  293. }
  294. static String cachedPreferences(String productName) {
  295. // ~/Library/Preferences/com.apple.java.util.prefs.plist
  296. // .java/.userPrefs/com/google/gwt/dev/shell/prefs.xml
  297. // HKEY_CURRENT_USER\SOFTWARE\JavaSoft\Prefs
  298. Preferences p = Preferences.userNodeForPackage(CvalInfo.class);
  299. return p.get(productName, null);
  300. }
  301. static void saveCache(String productName, String key, Boolean expired,
  302. Long expireTs, String type) {
  303. String json = responseJson.replace(productNameCval, productName);
  304. if (expired != null && expired) {
  305. expireTs = System.currentTimeMillis() - GRACE_DAYS_MSECS - 1000;
  306. }
  307. if (expireTs != null) {
  308. json = json.replace("1893511225000", "" + expireTs);
  309. }
  310. if (key != null) {
  311. json = json.replace(VALID_KEY, key);
  312. }
  313. if (type != null) {
  314. json = json.replace("normal", type);
  315. }
  316. cacheLicenseInfo(parseJson(json));
  317. }
  318. static void captureSystemOut() {
  319. outContent = new ByteArrayOutputStream();
  320. System.setOut(new PrintStream(outContent));
  321. }
  322. static String readSystemOut() {
  323. restoreSystemOut();
  324. return outContent.toString();
  325. }
  326. static void restoreSystemOut() {
  327. System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
  328. }
  329. @Test(expected = FileNotFoundException.class)
  330. public void testReadKeyFromFile_NonexistingLicenseFile() throws Exception {
  331. licenseChecker.readKeyFromFile(new URL("file:///foobar.baz"), 4);
  332. }
  333. @Test
  334. public void testReadKeyFromFile_LicenseFileEmpty() throws Exception {
  335. File tmpLicenseFile = File.createTempFile("license", "lic");
  336. assertNull(licenseChecker.readKeyFromFile(tmpLicenseFile.toURI()
  337. .toURL(), 4));
  338. tmpLicenseFile.delete();
  339. }
  340. @Test
  341. public void testReadKeyFromFile_LicenseFileHasSingleUnidentifiedKey()
  342. throws Exception {
  343. File tmpLicenseFile = File.createTempFile("license", "lic");
  344. PrintWriter out = new PrintWriter(tmpLicenseFile);
  345. out.println("this-is-a-license");
  346. out.close();
  347. assertEquals("this-is-a-license", licenseChecker.readKeyFromFile(
  348. tmpLicenseFile.toURI().toURL(), 4));
  349. tmpLicenseFile.delete();
  350. }
  351. @Test
  352. public void testReadKeyFromFile_LicenseFileHasSingleIdentifiedKey()
  353. throws Exception {
  354. File tmpLicenseFile = File.createTempFile("license", "lic");
  355. PrintWriter out = new PrintWriter(tmpLicenseFile);
  356. out.println("4=this-is-a-license");
  357. out.close();
  358. assertEquals("this-is-a-license", licenseChecker.readKeyFromFile(
  359. tmpLicenseFile.toURI().toURL(), 4));
  360. tmpLicenseFile.delete();
  361. }
  362. @Test
  363. public void testReadKeyFromFile_LicenseFileHasMultipleKeys()
  364. throws Exception {
  365. File tmpLicenseFile = File.createTempFile("license", "lic");
  366. PrintWriter out = new PrintWriter(tmpLicenseFile);
  367. out.println("4=this-is-a-license");
  368. out.println("5=this-is-another-license");
  369. out.close();
  370. assertEquals("this-is-a-license", licenseChecker.readKeyFromFile(
  371. tmpLicenseFile.toURI().toURL(), 4));
  372. assertEquals("this-is-another-license", licenseChecker.readKeyFromFile(
  373. tmpLicenseFile.toURI().toURL(), 5));
  374. tmpLicenseFile.delete();
  375. }
  376. @Test
  377. public void testReadKeyFromFile_LicenseFileHasMultipleKeysWithWhitespace()
  378. 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. assertEquals("this-is-a-license", licenseChecker.readKeyFromFile(
  385. tmpLicenseFile.toURI().toURL(), 4));
  386. assertEquals("this-is-another-license", licenseChecker.readKeyFromFile(
  387. tmpLicenseFile.toURI().toURL(), 5));
  388. tmpLicenseFile.delete();
  389. }
  390. @Test
  391. public void testReadKeyFromFile_RequestedVersionMissing() throws Exception {
  392. File tmpLicenseFile = File.createTempFile("license", "lic");
  393. PrintWriter out = new PrintWriter(tmpLicenseFile);
  394. out.println("4 = this-is-a-license");
  395. out.println("5 = this-is-another-license");
  396. out.close();
  397. assertNull(licenseChecker.readKeyFromFile(tmpLicenseFile.toURI()
  398. .toURL(), 3));
  399. tmpLicenseFile.delete();
  400. }
  401. @Test
  402. public void testReadKeyFromFile_FallbackToDefaultKey() throws Exception {
  403. File tmpLicenseFile = File.createTempFile("license", "lic");
  404. PrintWriter out = new PrintWriter(tmpLicenseFile);
  405. out.println("this-is-a-license");
  406. out.println("5 = this-is-another-license");
  407. out.close();
  408. assertEquals("this-is-a-license", licenseChecker.readKeyFromFile(tmpLicenseFile.toURI()
  409. .toURL(), 3));
  410. assertEquals("this-is-a-license", licenseChecker.readKeyFromFile(tmpLicenseFile.toURI()
  411. .toURL(), 4));
  412. assertEquals("this-is-another-license", licenseChecker.readKeyFromFile(
  413. tmpLicenseFile.toURI().toURL(), 5));
  414. tmpLicenseFile.delete();
  415. }
  416. @Test
  417. public void testReadKeyFromFile_FallbackToDefaultKeyReversed() throws Exception {
  418. File tmpLicenseFile = File.createTempFile("license", "lic");
  419. PrintWriter out = new PrintWriter(tmpLicenseFile);
  420. out.println("5 = this-is-another-license");
  421. out.println("this-is-a-license");
  422. out.close();
  423. assertEquals("this-is-a-license", licenseChecker.readKeyFromFile(tmpLicenseFile.toURI()
  424. .toURL(), 3));
  425. assertEquals("this-is-a-license", licenseChecker.readKeyFromFile(tmpLicenseFile.toURI()
  426. .toURL(), 4));
  427. assertEquals("this-is-another-license", licenseChecker.readKeyFromFile(
  428. tmpLicenseFile.toURI().toURL(), 5));
  429. tmpLicenseFile.delete();
  430. }
  431. }