ClsiCookieManagerTests.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. const sinon = require('sinon')
  2. const { assert, expect } = require('chai')
  3. const modulePath = '../../../../app/src/Features/Compile/ClsiCookieManager.js'
  4. const SandboxedModule = require('sandboxed-module')
  5. const realRequst = require('request')
  6. describe('ClsiCookieManager', function () {
  7. beforeEach(function () {
  8. this.redis = {
  9. auth() {},
  10. get: sinon.stub(),
  11. setex: sinon.stub().callsArg(3),
  12. }
  13. this.project_id = '123423431321-proj-id'
  14. this.user_id = 'abc-user-id'
  15. this.request = {
  16. post: sinon.stub(),
  17. cookie: realRequst.cookie,
  18. jar: realRequst.jar,
  19. defaults: () => {
  20. return this.request
  21. },
  22. }
  23. this.settings = {
  24. redis: {
  25. web: 'redis.something',
  26. },
  27. apis: {
  28. clsi: {
  29. url: 'http://clsi.example.com',
  30. },
  31. },
  32. clsiCookie: {
  33. ttlInSeconds: Math.random().toString(),
  34. ttlInSecondsRegular: Math.random().toString(),
  35. key: 'coooookie',
  36. },
  37. }
  38. this.requires = {
  39. '../../infrastructure/RedisWrapper': (this.RedisWrapper = {
  40. client: () => this.redis,
  41. }),
  42. '@overleaf/settings': this.settings,
  43. request: this.request,
  44. }
  45. this.ClsiCookieManager = SandboxedModule.require(modulePath, {
  46. requires: this.requires,
  47. })()
  48. })
  49. describe('getServerId', function () {
  50. it('should call get for the key', function (done) {
  51. this.redis.get.callsArgWith(1, null, 'clsi-7')
  52. this.ClsiCookieManager.getServerId(
  53. this.project_id,
  54. this.user_id,
  55. '',
  56. 'e2',
  57. (err, serverId) => {
  58. if (err) {
  59. return done(err)
  60. }
  61. this.redis.get
  62. .calledWith(`clsiserver:${this.project_id}:${this.user_id}`)
  63. .should.equal(true)
  64. serverId.should.equal('clsi-7')
  65. done()
  66. }
  67. )
  68. })
  69. it('should _populateServerIdViaRequest if no key is found', function (done) {
  70. this.ClsiCookieManager._populateServerIdViaRequest = sinon
  71. .stub()
  72. .yields(null)
  73. this.redis.get.callsArgWith(1, null)
  74. this.ClsiCookieManager.getServerId(
  75. this.project_id,
  76. this.user_id,
  77. '',
  78. (err, serverId) => {
  79. if (err) {
  80. return done(err)
  81. }
  82. this.ClsiCookieManager._populateServerIdViaRequest
  83. .calledWith(this.project_id, this.user_id)
  84. .should.equal(true)
  85. done()
  86. }
  87. )
  88. })
  89. it('should _populateServerIdViaRequest if no key is blank', function (done) {
  90. this.ClsiCookieManager._populateServerIdViaRequest = sinon
  91. .stub()
  92. .yields(null)
  93. this.redis.get.callsArgWith(1, null, '')
  94. this.ClsiCookieManager.getServerId(
  95. this.project_id,
  96. this.user_id,
  97. '',
  98. 'e2',
  99. (err, serverId) => {
  100. if (err) {
  101. return done(err)
  102. }
  103. this.ClsiCookieManager._populateServerIdViaRequest
  104. .calledWith(this.project_id, this.user_id)
  105. .should.equal(true)
  106. done()
  107. }
  108. )
  109. })
  110. })
  111. describe('_populateServerIdViaRequest', function () {
  112. beforeEach(function () {
  113. this.clsiServerId = 'server-id'
  114. this.ClsiCookieManager.setServerId = sinon.stub().yields()
  115. })
  116. describe('with a server id in the response', function () {
  117. beforeEach(function () {
  118. this.response = {
  119. headers: {
  120. 'set-cookie': [
  121. `${this.settings.clsiCookie.key}=${this.clsiServerId}`,
  122. ],
  123. },
  124. }
  125. this.request.post.callsArgWith(1, null, this.response)
  126. })
  127. it('should make a request to the clsi', function (done) {
  128. this.ClsiCookieManager._populateServerIdViaRequest(
  129. this.project_id,
  130. this.user_id,
  131. 'standard',
  132. 'e2',
  133. (err, serverId) => {
  134. if (err) {
  135. return done(err)
  136. }
  137. const args = this.ClsiCookieManager.setServerId.args[0]
  138. args[0].should.equal(this.project_id)
  139. args[1].should.equal(this.user_id)
  140. args[2].should.equal('standard')
  141. args[3].should.equal('e2')
  142. args[4].should.deep.equal(this.clsiServerId)
  143. done()
  144. }
  145. )
  146. })
  147. it('should return the server id', function (done) {
  148. this.ClsiCookieManager._populateServerIdViaRequest(
  149. this.project_id,
  150. this.user_id,
  151. '',
  152. 'e2',
  153. (err, serverId) => {
  154. if (err) {
  155. return done(err)
  156. }
  157. serverId.should.equal(this.clsiServerId)
  158. done()
  159. }
  160. )
  161. })
  162. })
  163. describe('without a server id in the response', function () {
  164. beforeEach(function () {
  165. this.response = { headers: {} }
  166. this.request.post.yields(null, this.response)
  167. })
  168. it('should not set the server id there is no server id in the response', function (done) {
  169. this.ClsiCookieManager._parseServerIdFromResponse = sinon
  170. .stub()
  171. .returns(null)
  172. this.ClsiCookieManager.setServerId(
  173. this.project_id,
  174. this.user_id,
  175. 'standard',
  176. 'e2',
  177. this.clsiServerId,
  178. null,
  179. err => {
  180. if (err) {
  181. return done(err)
  182. }
  183. this.redis.setex.called.should.equal(false)
  184. done()
  185. }
  186. )
  187. })
  188. })
  189. })
  190. describe('setServerId', function () {
  191. beforeEach(function () {
  192. this.clsiServerId = 'server-id'
  193. this.ClsiCookieManager._parseServerIdFromResponse = sinon
  194. .stub()
  195. .returns('clsi-8')
  196. })
  197. it('should set the server id with a ttl', function (done) {
  198. this.ClsiCookieManager.setServerId(
  199. this.project_id,
  200. this.user_id,
  201. 'standard',
  202. 'e2',
  203. this.clsiServerId,
  204. null,
  205. err => {
  206. if (err) {
  207. return done(err)
  208. }
  209. this.redis.setex.should.have.been.calledWith(
  210. `clsiserver:${this.project_id}:${this.user_id}`,
  211. this.settings.clsiCookie.ttlInSeconds,
  212. this.clsiServerId
  213. )
  214. done()
  215. }
  216. )
  217. })
  218. it('should set the server id with the regular ttl for reg instance', function (done) {
  219. this.clsiServerId = 'clsi-reg-8'
  220. this.ClsiCookieManager.setServerId(
  221. this.project_id,
  222. this.user_id,
  223. 'standard',
  224. 'e2',
  225. this.clsiServerId,
  226. null,
  227. err => {
  228. if (err) {
  229. return done(err)
  230. }
  231. expect(this.redis.setex).to.have.been.calledWith(
  232. `clsiserver:${this.project_id}:${this.user_id}`,
  233. this.settings.clsiCookie.ttlInSecondsRegular,
  234. this.clsiServerId
  235. )
  236. done()
  237. }
  238. )
  239. })
  240. it('should not set the server id if clsiCookies are not enabled', function (done) {
  241. delete this.settings.clsiCookie.key
  242. this.ClsiCookieManager = SandboxedModule.require(modulePath, {
  243. globals: {
  244. console,
  245. },
  246. requires: this.requires,
  247. })()
  248. this.ClsiCookieManager.setServerId(
  249. this.project_id,
  250. this.user_id,
  251. 'standard',
  252. 'e2',
  253. this.clsiServerId,
  254. null,
  255. err => {
  256. if (err) {
  257. return done(err)
  258. }
  259. this.redis.setex.called.should.equal(false)
  260. done()
  261. }
  262. )
  263. })
  264. it('should also set in the secondary if secondary redis is enabled', function (done) {
  265. this.redis_secondary = { setex: sinon.stub().callsArg(3) }
  266. this.settings.redis.clsi_cookie_secondary = {}
  267. this.RedisWrapper.client = sinon.stub()
  268. this.RedisWrapper.client.withArgs('clsi_cookie').returns(this.redis)
  269. this.RedisWrapper.client
  270. .withArgs('clsi_cookie_secondary')
  271. .returns(this.redis_secondary)
  272. this.ClsiCookieManager = SandboxedModule.require(modulePath, {
  273. globals: {
  274. console,
  275. },
  276. requires: this.requires,
  277. })()
  278. this.ClsiCookieManager._parseServerIdFromResponse = sinon
  279. .stub()
  280. .returns('clsi-8')
  281. this.ClsiCookieManager.setServerId(
  282. this.project_id,
  283. this.user_id,
  284. 'standard',
  285. 'e2',
  286. this.clsiServerId,
  287. null,
  288. err => {
  289. if (err) {
  290. return done(err)
  291. }
  292. this.redis_secondary.setex.should.have.been.calledWith(
  293. `clsiserver:${this.project_id}:${this.user_id}`,
  294. this.settings.clsiCookie.ttlInSeconds,
  295. this.clsiServerId
  296. )
  297. done()
  298. }
  299. )
  300. })
  301. })
  302. describe('getCookieJar', function () {
  303. beforeEach(function () {
  304. this.ClsiCookieManager.getServerId = sinon.stub().yields(null, 'clsi-11')
  305. })
  306. it('should return a jar with the cookie set populated from redis', function (done) {
  307. this.ClsiCookieManager.getCookieJar(
  308. this.project_id,
  309. this.user_id,
  310. '',
  311. 'e2',
  312. (err, jar) => {
  313. if (err) {
  314. return done(err)
  315. }
  316. jar._jar.store.idx['clsi.example.com']['/'][
  317. this.settings.clsiCookie.key
  318. ].key.should.equal
  319. jar._jar.store.idx['clsi.example.com']['/'][
  320. this.settings.clsiCookie.key
  321. ].value.should.equal('clsi-11')
  322. done()
  323. }
  324. )
  325. })
  326. it('should return empty cookie jar if clsiCookies are not enabled', function (done) {
  327. delete this.settings.clsiCookie.key
  328. this.ClsiCookieManager = SandboxedModule.require(modulePath, {
  329. globals: {
  330. console,
  331. },
  332. requires: this.requires,
  333. })()
  334. this.ClsiCookieManager.getCookieJar(
  335. this.project_id,
  336. this.user_id,
  337. '',
  338. 'e2',
  339. (err, jar) => {
  340. if (err) {
  341. return done(err)
  342. }
  343. assert.deepEqual(jar, realRequst.jar())
  344. done()
  345. }
  346. )
  347. })
  348. })
  349. })