Skip to content
Snippets Groups Projects
Select Git revision
  • aac2a4d5ad5f1a1494e1082a6da2a70e358643c0
  • master default protected
  • gh-pages
  • dependabot/npm_and_yarn/nock-14.0.9
  • dependabot/npm_and_yarn/react-19.1.1
  • dependabot/npm_and_yarn/react-dom-19.1.1
  • server-2025-08-01-57ada99c
  • server-2025-02-01-6100669a
  • server-2024-11-01-87cba042
  • server-2024-10-01-6875b7c8
  • dependabot/npm_and_yarn/path-to-regexp-8.2.0
  • server-2024-09-01-3d52575c
  • daily-tests-gha2
  • daily-tests-gha
  • server-2023-12-01-92d8fb8e
  • server-2023-11-01-a80c93fd
  • server-2023-10-01-31096085
  • coc-v2
  • server-2023-09-01-8edc3810
  • server-2023-08-01-75858a03
  • server-2023-07-01-02183d8d
  • server-2025-08-03
  • server-2025-07-01
  • 5.0.2
  • 5.0.1
  • 5.0.0
  • server-2025-06-01
  • server-2025-05-01
  • server-2025-04-03
  • server-2025-03-02
  • server-2025-03-01
  • server-2025-02-02
  • server-2025-01-01
  • server-2024-12-01
  • server-2024-11-02
  • 4.1.0
  • server-2024-09-25
  • server-2024-09-02
  • server-2024-08-01
  • server-2024-07-01
  • 4.0.0
41 results

legacy-request-handler.spec.js

Blame
  • legacy-request-handler.spec.js 11.26 KiB
    'use strict'
    
    const { expect } = require('chai')
    const fetch = require('node-fetch')
    const nock = require('nock')
    const portfinder = require('portfinder')
    const Camp = require('camp')
    const analytics = require('../server/analytics')
    const { makeBadgeData: getBadgeData } = require('../../lib/badge-data')
    const {
      handleRequest,
      clearRequestCache,
      _requestCache,
    } = require('./legacy-request-handler')
    
    async function performTwoRequests(baseUrl, first, second) {
      expect((await fetch(`${baseUrl}${first}`)).ok).to.be.true
      expect((await fetch(`${baseUrl}${second}`)).ok).to.be.true
    }
    
    function fakeHandler(queryParams, match, sendBadge, request) {
      const [, someValue, format] = match
      const badgeData = getBadgeData('testing', queryParams)
      badgeData.text[1] = someValue
      sendBadge(format, badgeData)
    }
    
    function createFakeHandlerWithCacheLength(cacheLengthSeconds) {
      return function fakeHandler(queryParams, match, sendBadge, request) {
        const [, someValue, format] = match
        const badgeData = getBadgeData('testing', queryParams)
        badgeData.text[1] = someValue
        badgeData.cacheLengthSeconds = cacheLengthSeconds
        sendBadge(format, badgeData)
      }
    }
    
    function fakeHandlerWithNetworkIo(queryParams, match, sendBadge, request) {
      const [, someValue, format] = match
      request('https://www.google.com/foo/bar', (err, res, buffer) => {
        const badgeData = getBadgeData('testing', queryParams)
        if (err) {
          badgeData.text[1] = err.prettyMessage
          sendBadge(format, badgeData)
          return
        }
        badgeData.text[1] = someValue
        sendBadge(format, badgeData)
      })
    }
    
    describe('The request handler', function() {
      before(analytics.load)
    
      let port, baseUrl
      beforeEach(async function() {
        port = await portfinder.getPortPromise()
        baseUrl = `http://127.0.0.1:${port}`
      })
    
      let camp
      beforeEach(function(done) {
        camp = Camp.start({ port, hostname: '::' })
        camp.on('listening', () => done())
      })
      afterEach(function(done) {
        clearRequestCache()
        if (camp) {
          camp.close(() => done())
          camp = null
        }
      })
    
      const standardCacheHeaders = { defaultCacheLengthSeconds: 120 }
    
      describe('the options object calling style', function() {
        beforeEach(function() {
          camp.route(
            /^\/testing\/([^/]+)\.(svg|png|gif|jpg|json)$/,
            handleRequest(standardCacheHeaders, { handler: fakeHandler })
          )
        })
    
        it('should return the expected response', async function() {
          const res = await fetch(`${baseUrl}/testing/123.json`)
          expect(res.ok).to.be.true
          expect(await res.json()).to.deep.equal({ name: 'testing', value: '123' })
        })
      })
    
      describe('the function shorthand calling style', function() {
        beforeEach(function() {
          camp.route(
            /^\/testing\/([^/]+)\.(svg|png|gif|jpg|json)$/,
            handleRequest(standardCacheHeaders, fakeHandler)
          )
        })
    
        it('should return the expected response', async function() {
          const res = await fetch(`${baseUrl}/testing/123.json`)
          expect(res.ok).to.be.true
          expect(await res.json()).to.deep.equal({ name: 'testing', value: '123' })
        })
      })
    
      describe('the response size limit', function() {
        beforeEach(function() {
          camp.route(
            /^\/testing\/([^/]+)\.(svg|png|gif|jpg|json)$/,
            handleRequest(standardCacheHeaders, {
              handler: fakeHandlerWithNetworkIo,
              fetchLimitBytes: 100,
            })
          )
        })
    
        it('should not throw an error if the response <= fetchLimitBytes', async function() {
          nock('https://www.google.com')
            .get('/foo/bar')
            .once()
            .reply(200, 'x'.repeat(100))
          const res = await fetch(`${baseUrl}/testing/123.json`)
          expect(res.ok).to.be.true
          expect(await res.json()).to.deep.equal({
            name: 'testing',
            value: '123',
          })
        })
    
        it('should throw an error if the response is > fetchLimitBytes', async function() {
          nock('https://www.google.com')
            .get('/foo/bar')
            .once()
            .reply(200, 'x'.repeat(101))
          const res = await fetch(`${baseUrl}/testing/123.json`)
          expect(res.ok).to.be.true
          expect(await res.json()).to.deep.equal({
            name: 'testing',
            value: 'Maximum response size exceeded',
          })
        })
    
        afterEach(function() {
          nock.cleanAll()
        })
      })
    
      describe('caching', function() {
        describe('standard query parameters', function() {
          let handlerCallCount
          beforeEach(function() {
            handlerCallCount = 0
          })
    
          function register({ cacheHeaderConfig }) {
            camp.route(
              /^\/testing\/([^/]+)\.(svg|png|gif|jpg|json)$/,
              handleRequest(
                cacheHeaderConfig,
                (queryParams, match, sendBadge, request) => {
                  ++handlerCallCount
                  fakeHandler(queryParams, match, sendBadge, request)
                }
              )
            )
          }
    
          context('With standard cache settings', function() {
            beforeEach(function() {
              register({ cacheHeaderConfig: standardCacheHeaders })
            })
    
            it('should cache identical requests', async function() {
              await performTwoRequests(
                baseUrl,
                '/testing/123.svg',
                '/testing/123.svg'
              )
              expect(handlerCallCount).to.equal(1)
            })
    
            it('should differentiate known query parameters', async function() {
              await performTwoRequests(
                baseUrl,
                '/testing/123.svg?label=foo',
                '/testing/123.svg?label=bar'
              )
              expect(handlerCallCount).to.equal(2)
            })
    
            it('should ignore unknown query parameters', async function() {
              await performTwoRequests(
                baseUrl,
                '/testing/123.svg?foo=1',
                '/testing/123.svg?foo=2'
              )
              expect(handlerCallCount).to.equal(1)
            })
          })
    
          it('should set the expires header to current time + defaultCacheLengthSeconds', async function() {
            register({ cacheHeaderConfig: { defaultCacheLengthSeconds: 900 } })
            const res = await fetch(`${baseUrl}/testing/123.json`)
            const expectedExpiry = new Date(
              +new Date(res.headers.get('date')) + 900000
            ).toGMTString()
            expect(res.headers.get('expires')).to.equal(expectedExpiry)
            expect(res.headers.get('cache-control')).to.equal('max-age=900')
          })
    
          it('should set the expected cache headers on cached responses', async function() {
            register({ cacheHeaderConfig: { defaultCacheLengthSeconds: 900 } })
    
            // Make first request.
            await fetch(`${baseUrl}/testing/123.json`)
    
            const res = await fetch(`${baseUrl}/testing/123.json`)
            const expectedExpiry = new Date(
              +new Date(res.headers.get('date')) + 900000
            ).toGMTString()
            expect(res.headers.get('expires')).to.equal(expectedExpiry)
            expect(res.headers.get('cache-control')).to.equal('max-age=900')
          })
    
          it('should let live service data override the default cache headers with longer value', async function() {
            camp.route(
              /^\/testing\/([^/]+)\.(svg|png|gif|jpg|json)$/,
              handleRequest(
                { defaultCacheLengthSeconds: 300 },
                (queryParams, match, sendBadge, request) => {
                  ++handlerCallCount
                  createFakeHandlerWithCacheLength(400)(
                    queryParams,
                    match,
                    sendBadge,
                    request
                  )
                }
              )
            )
    
            const res = await fetch(`${baseUrl}/testing/123.json`)
            expect(res.headers.get('cache-control')).to.equal('max-age=400')
          })
    
          it('should not let live service data override the default cache headers with shorter value', async function() {
            camp.route(
              /^\/testing\/([^/]+)\.(svg|png|gif|jpg|json)$/,
              handleRequest(
                { defaultCacheLengthSeconds: 300 },
                (queryParams, match, sendBadge, request) => {
                  ++handlerCallCount
                  createFakeHandlerWithCacheLength(200)(
                    queryParams,
                    match,
                    sendBadge,
                    request
                  )
                }
              )
            )
    
            const res = await fetch(`${baseUrl}/testing/123.json`)
            expect(res.headers.get('cache-control')).to.equal('max-age=300')
          })
    
          it('should set the expires header to current time + maxAge', async function() {
            register({ cacheHeaderConfig: { defaultCacheLengthSeconds: 0 } })
            const res = await fetch(`${baseUrl}/testing/123.json?maxAge=3600`)
            const expectedExpiry = new Date(
              +new Date(res.headers.get('date')) + 3600000
            ).toGMTString()
            expect(res.headers.get('expires')).to.equal(expectedExpiry)
            expect(res.headers.get('cache-control')).to.equal('max-age=3600')
          })
    
          it('should ignore maxAge if maxAge < defaultCacheLengthSeconds', async function() {
            register({ cacheHeaderConfig: { defaultCacheLengthSeconds: 600 } })
            const res = await fetch(`${baseUrl}/testing/123.json?maxAge=300`)
            const expectedExpiry = new Date(
              +new Date(res.headers.get('date')) + 600000
            ).toGMTString()
            expect(res.headers.get('expires')).to.equal(expectedExpiry)
            expect(res.headers.get('cache-control')).to.equal('max-age=600')
          })
    
          it('should set Cache-Control: no-cache, no-store, must-revalidate if maxAge=0', async function() {
            register({ cacheHeaderConfig: { defaultCacheLengthSeconds: 0 } })
            const res = await fetch(`${baseUrl}/testing/123.json`)
            expect(res.headers.get('expires')).to.equal(res.headers.get('date'))
            expect(res.headers.get('cache-control')).to.equal(
              'no-cache, no-store, must-revalidate'
            )
          })
    
          describe('the cache key', function() {
            beforeEach(function() {
              register({ cacheHeaderConfig: standardCacheHeaders })
            })
            const expectedCacheKey = '/testing/123.json?colorB=123&label=foo'
            it('should match expected and use canonical order - 1', async function() {
              const res = await fetch(
                `${baseUrl}/testing/123.json?colorB=123&label=foo`
              )
              expect(res.ok).to.be.true
              expect(_requestCache.cache).to.have.keys(expectedCacheKey)
            })
            it('should match expected and use canonical order - 2', async function() {
              const res = await fetch(
                `${baseUrl}/testing/123.json?label=foo&colorB=123`
              )
              expect(res.ok).to.be.true
              expect(_requestCache.cache).to.have.keys(expectedCacheKey)
            })
          })
        })
    
        describe('custom query parameters', function() {
          let handlerCallCount
          beforeEach(function() {
            handlerCallCount = 0
            camp.route(
              /^\/testing\/([^/]+)\.(svg|png|gif|jpg|json)$/,
              handleRequest(standardCacheHeaders, {
                queryParams: ['foo'],
                handler: (queryParams, match, sendBadge, request) => {
                  ++handlerCallCount
                  fakeHandler(queryParams, match, sendBadge, request)
                },
              })
            )
          })
    
          it('should differentiate them', async function() {
            await performTwoRequests(
              baseUrl,
              '/testing/123.svg?foo=1',
              '/testing/123.svg?foo=2'
            )
            expect(handlerCallCount).to.equal(2)
          })
        })
      })
    })