basic.test.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. const { eq, ok, notOk, deepEq, throwsAsync } = require('../../helpers/assert');
  2. const { makeNetwork, makePeer } = require('../../helpers/setup');
  3. describe('tribes: create + list', (t) => {
  4. t('A creates private tribe, sees it in listAll', async () => {
  5. const net = makeNetwork();
  6. const A = makePeer(net); A.setActor();
  7. const tm = A.use('tribes');
  8. const r = await tm.createTribe('Secret', 'd', null, '', [], false, true, 'strict', null, 'OPEN', '');
  9. const list = await tm.listAll();
  10. eq(list.length, 1);
  11. eq(list[0].title, 'Secret');
  12. eq(list[0].id, r.key);
  13. });
  14. t('A creates public tribe, outsider B sees it', async () => {
  15. const net = makeNetwork();
  16. const A = makePeer(net); const B = makePeer(net);
  17. A.setActor();
  18. await A.use('tribes').createTribe('Public', '', null, '', [], false, false, 'strict', null, 'OPEN', '');
  19. B.setActor();
  20. const list = await B.use('tribes').listAll();
  21. eq(list.length, 1);
  22. eq(list[0].title, 'Public');
  23. });
  24. t('outsider B does NOT see private tribe', async () => {
  25. const net = makeNetwork();
  26. const A = makePeer(net); const B = makePeer(net);
  27. A.setActor();
  28. await A.use('tribes').createTribe('Hidden', '', null, '', [], false, true, 'strict', null, 'OPEN', '');
  29. B.setActor();
  30. eq((await B.use('tribes').listAll()).length, 0);
  31. });
  32. t('private tribe envelope is opaque (no plaintext leak in log)', async () => {
  33. const net = makeNetwork();
  34. const A = makePeer(net); A.setActor();
  35. await A.use('tribes').createTribe('TopSecret', 'sensitive', null, '', ['x'], false, true, 'strict', null, 'OPEN', '');
  36. const wrapped = net.log.find(m => m.value.content && m.value.content.type === 'tribe-msg');
  37. ok(wrapped);
  38. notOk(net.log.find(m => {
  39. const c = m.value && m.value.content;
  40. return c && (c.title === 'TopSecret' || (c.type === 'tribe' && c.title));
  41. }));
  42. });
  43. });
  44. describe('tribes: invite + join', (t) => {
  45. t('A creates private tribe, generates invite, B joins → Members:2', async () => {
  46. const net = makeNetwork();
  47. const A = makePeer(net); const B = makePeer(net);
  48. A.setActor();
  49. const tmA = A.use('tribes');
  50. const r = await tmA.createTribe('Club', '', null, '', [], false, true, 'strict', null, 'OPEN', '');
  51. const code = await tmA.generateInvite(r.key);
  52. eq(typeof code, 'string'); eq(code.length, 32);
  53. B.setActor();
  54. const joined = await B.use('tribes').joinByInvite(code);
  55. eq(joined, r.key);
  56. const tribeB = await B.use('tribes').getTribeById(r.key);
  57. eq(tribeB.members.length, 2);
  58. A.setActor();
  59. const tribeA = await tmA.getTribeById(r.key);
  60. eq(tribeA.members.length, 2);
  61. ok(tribeA.members.includes(B.keypair.id));
  62. });
  63. t('B cannot join with wrong code', async () => {
  64. const net = makeNetwork();
  65. const A = makePeer(net); const B = makePeer(net);
  66. A.setActor();
  67. const r = await A.use('tribes').createTribe('X', '', null, '', [], false, true, 'strict', null, 'OPEN', '');
  68. await A.use('tribes').generateInvite(r.key);
  69. B.setActor();
  70. await throwsAsync(() => B.use('tribes').joinByInvite('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'), 'Invalid');
  71. });
  72. t('outsider C cannot reuse invite after B consumed it', async () => {
  73. const net = makeNetwork();
  74. const A = makePeer(net); const B = makePeer(net); const C = makePeer(net);
  75. A.setActor();
  76. const r = await A.use('tribes').createTribe('X', '', null, '', [], false, true, 'strict', null, 'OPEN', '');
  77. const code = await A.use('tribes').generateInvite(r.key);
  78. B.setActor();
  79. await B.use('tribes').joinByInvite(code);
  80. C.setActor();
  81. await throwsAsync(() => C.use('tribes').joinByInvite(code), 'Invalid');
  82. });
  83. });
  84. describe('tribes: content', (t) => {
  85. t('A publishes feed in tribe, B (member) reads it', async () => {
  86. const net = makeNetwork();
  87. const A = makePeer(net); const B = makePeer(net);
  88. A.setActor();
  89. const r = await A.use('tribes').createTribe('G', '', null, '', [], false, true, 'strict', null, 'OPEN', '');
  90. const code = await A.use('tribes').generateInvite(r.key);
  91. B.setActor();
  92. await B.use('tribes').joinByInvite(code);
  93. A.setActor();
  94. await A.use('tribesContent').create(r.key, 'feed', { description: 'hi B' });
  95. B.setActor();
  96. const items = await B.use('tribesContent').listByTribe(r.key, 'feed');
  97. eq(items.length, 1);
  98. eq(items[0].description, 'hi B');
  99. });
  100. t('non-member sees no tribe-content', async () => {
  101. const net = makeNetwork();
  102. const A = makePeer(net); const C = makePeer(net);
  103. A.setActor();
  104. const r = await A.use('tribes').createTribe('G', '', null, '', [], false, true, 'strict', null, 'OPEN', '');
  105. await A.use('tribesContent').create(r.key, 'feed', { description: 'private' });
  106. C.setActor();
  107. eq((await C.use('tribesContent').listByTribe(r.key, 'feed')).length, 0);
  108. });
  109. });
  110. describe('tribes: invariants', (t) => {
  111. t('multiple updates resolve to single tribe with latest tip', async () => {
  112. const net = makeNetwork();
  113. const A = makePeer(net); A.setActor();
  114. const r = await A.use('tribes').createTribe('X', '', null, '', [], false, true, 'strict', null, 'OPEN', '');
  115. await A.use('tribes').updateTribeById(r.key, { description: 'a' });
  116. await A.use('tribes').updateTribeById(r.key, { description: 'b' });
  117. const list = await A.use('tribes').listAll();
  118. eq(list.length, 1);
  119. eq(list[0].description, 'b');
  120. });
  121. t('getChainIds returns full chain', async () => {
  122. const net = makeNetwork();
  123. const A = makePeer(net); A.setActor();
  124. const r = await A.use('tribes').createTribe('X', '', null, '', [], false, true, 'strict', null, 'OPEN', '');
  125. await A.use('tribes').updateTribeById(r.key, { description: '1' });
  126. await A.use('tribes').updateTribeById(r.key, { description: '2' });
  127. const chain = await A.use('tribes').getChainIds(r.key);
  128. eq(chain.length, 3);
  129. eq(chain[0], r.key);
  130. });
  131. });