Skip to content

Commit

Permalink
fix: use a better chunking function
Browse files Browse the repository at this point in the history
  • Loading branch information
bahmutov committed Jan 18, 2023
1 parent 92f1572 commit b8083d0
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 21 deletions.
58 changes: 58 additions & 0 deletions cypress/e2e/chunks.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const { getChunk, chunkify } = require('../../src/chunk')

describe('getChunk', () => {
it('splits 4 specs across 4 machines', () => {
const specs = [1, 2, 3, 4]
let chunk = getChunk(specs, 4, 0)
expect(chunk, 'chunk 0').to.deep.equal([1])
chunk = getChunk(specs, 4, 1)
expect(chunk, 'chunk 1').to.deep.equal([2])
chunk = getChunk(specs, 4, 2)
expect(chunk, 'chunk 2').to.deep.equal([3])
chunk = getChunk(specs, 4, 3)
expect(chunk, 'chunk 3').to.deep.equal([4])
})

it('splits 5 specs across 4 machines', () => {
const specs = [1, 2, 3, 4, 5]
let chunk = getChunk(specs, 4, 0)
expect(chunk, 'chunk 0').to.deep.equal([1, 2])
chunk = getChunk(specs, 4, 1)
expect(chunk, 'chunk 1').to.deep.equal([3])
chunk = getChunk(specs, 4, 2)
expect(chunk, 'chunk 2').to.deep.equal([4])
chunk = getChunk(specs, 4, 3)
expect(chunk, 'chunk 3').to.deep.equal([5])
})

it('splits 1 spec across 2 machines', () => {
const specs = [1]
let chunk = getChunk(specs, 2, 0)
expect(chunk, 'chunk 0').to.deep.equal([1])
chunk = getChunk(specs, 2, 1)
expect(chunk, 'chunk 1').to.deep.equal(undefined)
})
})

describe('chunkify', () => {
it('splits 5 specs across 1 machine', () => {
const specs = [1, 2, 3, 4, 5]
const chunks = chunkify(specs, 1, true)
expect(chunks).to.deep.equal([[1, 2, 3, 4, 5]])
})

it('splits 5 specs across 2 machines', () => {
const specs = [1, 2, 3, 4, 5]
const chunks = chunkify(specs, 2, true)
expect(chunks).to.deep.equal([
[1, 2, 3],
[4, 5],
])
})

it('splits 5 specs across 6 machines', () => {
const specs = [1, 2, 3, 4, 5]
const chunks = chunkify(specs, 6, true)
expect(chunks).to.deep.equal([[1], [2], [3], [4], [5]])
})
})
49 changes: 49 additions & 0 deletions src/chunk.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// https://stackoverflow.com/questions/8188548/splitting-a-js-array-into-n-arrays
function chunkify(a, n, balanced) {
if (n < 2) return [a]

var len = a.length,
out = [],
i = 0,
size

if (len % n === 0) {
size = Math.floor(len / n)
while (i < len) {
out.push(a.slice(i, (i += size)))
}
} else if (balanced) {
while (i < len) {
size = Math.ceil((len - i) / n--)
out.push(a.slice(i, (i += size)))
}
} else {
n--
size = Math.floor(len / n)
if (len % size === 0) size--
while (i < size * n) {
out.push(a.slice(i, (i += size)))
}
out.push(a.slice(size * n))
}

return out
}

function getChunk(values, totalChunks, chunkIndex) {
// split all items into N chunks and take just a single chunk
if (totalChunks < 0) {
throw new Error('totalChunks must be >= 0')
}

if (chunkIndex < 0 || chunkIndex >= totalChunks) {
throw new Error(
`Invalid chunk index ${chunkIndex} vs all chunks ${totalChunks}`,
)
}

const chunks = chunkify(values, totalChunks, true)
return chunks[chunkIndex]
}

module.exports = { getChunk, chunkify }
24 changes: 3 additions & 21 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,7 @@ const debug = require('debug')('cypress-split')
const { getSpecs } = require('find-cypress-specs')
const ghCore = require('@actions/core')
const cTable = require('console.table')

function getChunk(values, totalChunks, chunkIndex) {
debug('get chunk %o', { values, totalChunks, chunkIndex })

// split all items into N chunks and take just a single chunk
if (totalChunks < 0) {
throw new Error('totalChunks must be >= 0')
}

if (chunkIndex < 0 || chunkIndex >= totalChunks) {
throw new Error(
`Invalid chunk index ${chunkIndex} vs all chunks ${totalChunks}`,
)
}

const chunkSize = Math.ceil(values.length / totalChunks)
const chunkStart = chunkIndex * chunkSize
const chunkEnd = chunkStart + chunkSize
const chunk = values.slice(chunkStart, chunkEnd)
return chunk
}
const { getChunk } = require('./chunk')

const label = 'cypress-split:'

Expand Down Expand Up @@ -104,6 +84,8 @@ function cypressSplit(on, config) {
const splitN = Number(SPLIT)
const splitIndex = Number(SPLIT_INDEX)
console.log('%s split %d of %d', label, splitIndex, splitN)

debug('get chunk %o', { values, totalChunks, chunkIndex })
const splitSpecs = getChunk(specs, splitN, splitIndex)

const specRows = splitSpecs.map((specName, k) => {
Expand Down

0 comments on commit b8083d0

Please sign in to comment.