AccessControl.behavior.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers');
  2. const { expect } = require('chai');
  3. const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior');
  4. const DEFAULT_ADMIN_ROLE = '0x0000000000000000000000000000000000000000000000000000000000000000';
  5. const ROLE = web3.utils.soliditySha3('ROLE');
  6. const OTHER_ROLE = web3.utils.soliditySha3('OTHER_ROLE');
  7. function shouldBehaveLikeAccessControl (errorPrefix, admin, authorized, other, otherAdmin, otherAuthorized) {
  8. shouldSupportInterfaces(['AccessControl']);
  9. describe('default admin', function () {
  10. it('deployer has default admin role', async function () {
  11. expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, admin)).to.equal(true);
  12. });
  13. it('other roles\'s admin is the default admin role', async function () {
  14. expect(await this.accessControl.getRoleAdmin(ROLE)).to.equal(DEFAULT_ADMIN_ROLE);
  15. });
  16. it('default admin role\'s admin is itself', async function () {
  17. expect(await this.accessControl.getRoleAdmin(DEFAULT_ADMIN_ROLE)).to.equal(DEFAULT_ADMIN_ROLE);
  18. });
  19. });
  20. describe('granting', function () {
  21. it('admin can grant role to other accounts', async function () {
  22. const receipt = await this.accessControl.grantRole(ROLE, authorized, { from: admin });
  23. expectEvent(receipt, 'RoleGranted', { account: authorized, role: ROLE, sender: admin });
  24. expect(await this.accessControl.hasRole(ROLE, authorized)).to.equal(true);
  25. });
  26. it('non-admin cannot grant role to other accounts', async function () {
  27. await expectRevert(
  28. this.accessControl.grantRole(ROLE, authorized, { from: other }),
  29. `${errorPrefix}: sender must be an admin to grant`,
  30. );
  31. });
  32. it('accounts can be granted a role multiple times', async function () {
  33. await this.accessControl.grantRole(ROLE, authorized, { from: admin });
  34. const receipt = await this.accessControl.grantRole(ROLE, authorized, { from: admin });
  35. expectEvent.notEmitted(receipt, 'RoleGranted');
  36. });
  37. });
  38. describe('revoking', function () {
  39. it('roles that are not had can be revoked', async function () {
  40. expect(await this.accessControl.hasRole(ROLE, authorized)).to.equal(false);
  41. const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: admin });
  42. expectEvent.notEmitted(receipt, 'RoleRevoked');
  43. });
  44. context('with granted role', function () {
  45. beforeEach(async function () {
  46. await this.accessControl.grantRole(ROLE, authorized, { from: admin });
  47. });
  48. it('admin can revoke role', async function () {
  49. const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: admin });
  50. expectEvent(receipt, 'RoleRevoked', { account: authorized, role: ROLE, sender: admin });
  51. expect(await this.accessControl.hasRole(ROLE, authorized)).to.equal(false);
  52. });
  53. it('non-admin cannot revoke role', async function () {
  54. await expectRevert(
  55. this.accessControl.revokeRole(ROLE, authorized, { from: other }),
  56. `${errorPrefix}: sender must be an admin to revoke`,
  57. );
  58. });
  59. it('a role can be revoked multiple times', async function () {
  60. await this.accessControl.revokeRole(ROLE, authorized, { from: admin });
  61. const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: admin });
  62. expectEvent.notEmitted(receipt, 'RoleRevoked');
  63. });
  64. });
  65. });
  66. describe('renouncing', function () {
  67. it('roles that are not had can be renounced', async function () {
  68. const receipt = await this.accessControl.renounceRole(ROLE, authorized, { from: authorized });
  69. expectEvent.notEmitted(receipt, 'RoleRevoked');
  70. });
  71. context('with granted role', function () {
  72. beforeEach(async function () {
  73. await this.accessControl.grantRole(ROLE, authorized, { from: admin });
  74. });
  75. it('bearer can renounce role', async function () {
  76. const receipt = await this.accessControl.renounceRole(ROLE, authorized, { from: authorized });
  77. expectEvent(receipt, 'RoleRevoked', { account: authorized, role: ROLE, sender: authorized });
  78. expect(await this.accessControl.hasRole(ROLE, authorized)).to.equal(false);
  79. });
  80. it('only the sender can renounce their roles', async function () {
  81. await expectRevert(
  82. this.accessControl.renounceRole(ROLE, authorized, { from: admin }),
  83. `${errorPrefix}: can only renounce roles for self`,
  84. );
  85. });
  86. it('a role can be renounced multiple times', async function () {
  87. await this.accessControl.renounceRole(ROLE, authorized, { from: authorized });
  88. const receipt = await this.accessControl.renounceRole(ROLE, authorized, { from: authorized });
  89. expectEvent.notEmitted(receipt, 'RoleRevoked');
  90. });
  91. });
  92. });
  93. describe('setting role admin', function () {
  94. beforeEach(async function () {
  95. const receipt = await this.accessControl.setRoleAdmin(ROLE, OTHER_ROLE);
  96. expectEvent(receipt, 'RoleAdminChanged', {
  97. role: ROLE,
  98. previousAdminRole: DEFAULT_ADMIN_ROLE,
  99. newAdminRole: OTHER_ROLE,
  100. });
  101. await this.accessControl.grantRole(OTHER_ROLE, otherAdmin, { from: admin });
  102. });
  103. it('a role\'s admin role can be changed', async function () {
  104. expect(await this.accessControl.getRoleAdmin(ROLE)).to.equal(OTHER_ROLE);
  105. });
  106. it('the new admin can grant roles', async function () {
  107. const receipt = await this.accessControl.grantRole(ROLE, authorized, { from: otherAdmin });
  108. expectEvent(receipt, 'RoleGranted', { account: authorized, role: ROLE, sender: otherAdmin });
  109. });
  110. it('the new admin can revoke roles', async function () {
  111. await this.accessControl.grantRole(ROLE, authorized, { from: otherAdmin });
  112. const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: otherAdmin });
  113. expectEvent(receipt, 'RoleRevoked', { account: authorized, role: ROLE, sender: otherAdmin });
  114. });
  115. it('a role\'s previous admins no longer grant roles', async function () {
  116. await expectRevert(
  117. this.accessControl.grantRole(ROLE, authorized, { from: admin }),
  118. 'AccessControl: sender must be an admin to grant',
  119. );
  120. });
  121. it('a role\'s previous admins no longer revoke roles', async function () {
  122. await expectRevert(
  123. this.accessControl.revokeRole(ROLE, authorized, { from: admin }),
  124. 'AccessControl: sender must be an admin to revoke',
  125. );
  126. });
  127. });
  128. }
  129. function shouldBehaveLikeAccessControlEnumerable (errorPrefix, admin, authorized, other, otherAdmin, otherAuthorized) {
  130. shouldSupportInterfaces(['AccessControlEnumerable']);
  131. describe('enumerating', function () {
  132. it('role bearers can be enumerated', async function () {
  133. await this.accessControl.grantRole(ROLE, authorized, { from: admin });
  134. await this.accessControl.grantRole(ROLE, other, { from: admin });
  135. await this.accessControl.grantRole(ROLE, otherAuthorized, { from: admin });
  136. await this.accessControl.revokeRole(ROLE, other, { from: admin });
  137. const memberCount = await this.accessControl.getRoleMemberCount(ROLE);
  138. expect(memberCount).to.bignumber.equal('2');
  139. const bearers = [];
  140. for (let i = 0; i < memberCount; ++i) {
  141. bearers.push(await this.accessControl.getRoleMember(ROLE, i));
  142. }
  143. expect(bearers).to.have.members([authorized, otherAuthorized]);
  144. });
  145. });
  146. }
  147. module.exports = {
  148. shouldBehaveLikeAccessControl,
  149. shouldBehaveLikeAccessControlEnumerable,
  150. };