mirror of https://github.com/rancher/dashboard.git
445 lines
9.9 KiB
TypeScript
445 lines
9.9 KiB
TypeScript
import { convert, matching, parse, simplify } from '@shell/utils/selector';
|
|
|
|
describe('fx: parse', () => {
|
|
describe('using operator In', () => {
|
|
it.each([
|
|
['key=value'],
|
|
['key= value'],
|
|
['key =value'],
|
|
['key = value'],
|
|
[' key = value '],
|
|
['key==value'],
|
|
['key== value'],
|
|
['key ==value'],
|
|
['key == value'],
|
|
[' key == value '],
|
|
['key in (value)'],
|
|
[' key IN ( value ) '],
|
|
['key in(value)'],
|
|
])('should parse expression "%p" to selector', (expression) => {
|
|
const expected = {
|
|
key: 'key',
|
|
operator: 'In',
|
|
values: ['value']
|
|
};
|
|
|
|
const result = parse(expression);
|
|
|
|
expect(result).toStrictEqual([expected]);
|
|
});
|
|
|
|
it.each([
|
|
['some.prefix/key=value'],
|
|
['some.prefix/key= value'],
|
|
['some.prefix/key =value'],
|
|
['some.prefix/key = value'],
|
|
[' some.prefix/key = value '],
|
|
])('should parse expression with a path "%p" to selector', (expression) => {
|
|
const expected = {
|
|
key: 'some.prefix/key',
|
|
operator: 'In',
|
|
values: ['value']
|
|
};
|
|
|
|
const result = parse(expression);
|
|
|
|
expect(result).toStrictEqual([expected]);
|
|
});
|
|
|
|
it.each([
|
|
['key+in+(value1,value2)'],
|
|
['key IN( value1 , value2 )'],
|
|
])('should parse expression "%p" to selector with multiple values', (expression) => {
|
|
const expected = {
|
|
key: 'key',
|
|
operator: 'In',
|
|
values: ['value1', 'value2']
|
|
};
|
|
|
|
const result = parse(expression);
|
|
|
|
expect(result).toStrictEqual([expected]);
|
|
});
|
|
});
|
|
|
|
describe('using operator NotIn', () => {
|
|
it.each([
|
|
['key!=value'],
|
|
['key!= value'],
|
|
['key !=value'],
|
|
['key != value'],
|
|
[' key != value '],
|
|
])('should parse expression "%p" to selector', (expression) => {
|
|
const expected = {
|
|
key: 'key',
|
|
operator: 'NotIn',
|
|
values: ['value']
|
|
};
|
|
|
|
const result = parse(expression);
|
|
|
|
expect(result).toStrictEqual([expected]);
|
|
});
|
|
|
|
it.each([
|
|
['some.prefix/key!=value'],
|
|
['some.prefix/key!= value'],
|
|
['some.prefix/key !=value'],
|
|
['some.prefix/key != value'],
|
|
[' some.prefix/key != value '],
|
|
['some.prefix/key notin (value)'],
|
|
[' some.prefix/key NOTIN ( value ) '],
|
|
['some.prefix/key Not In(value)'],
|
|
['some.prefix/key NotIn(value)'],
|
|
])('should parse expression with a path "%p" to selector', (expression) => {
|
|
const expected = {
|
|
key: 'some.prefix/key',
|
|
operator: 'NotIn',
|
|
values: ['value']
|
|
};
|
|
|
|
const result = parse(expression);
|
|
|
|
expect(result).toStrictEqual([expected]);
|
|
});
|
|
|
|
it.each([
|
|
['key+NOTIN+(value1,value2)'],
|
|
['key notin (value1,value2)'],
|
|
['key not in (value1,value2)'],
|
|
['key notIn( value1 , value2 )'],
|
|
])('should parse expression "%p" to selector with multiple values', (expression) => {
|
|
const expected = {
|
|
key: 'key',
|
|
operator: 'NotIn',
|
|
values: ['value1', 'value2']
|
|
};
|
|
|
|
const result = parse(expression);
|
|
|
|
expect(result).toStrictEqual([expected]);
|
|
});
|
|
});
|
|
|
|
describe('using operator Exists', () => {
|
|
it.each([
|
|
['key'],
|
|
[' key'],
|
|
[' key '],
|
|
])('should parse expression "%p" to selector', (expression) => {
|
|
const expected = {
|
|
key: 'key',
|
|
operator: 'Exists',
|
|
};
|
|
|
|
const result = parse(expression);
|
|
|
|
expect(result).toStrictEqual([expected]);
|
|
});
|
|
|
|
it.each([
|
|
[' some.prefix/key-bar_baz '],
|
|
])('should parse expression with a path "%p" to selector', (expression) => {
|
|
const expected = {
|
|
key: 'some.prefix/key-bar_baz',
|
|
operator: 'Exists',
|
|
};
|
|
const result = parse(expression);
|
|
|
|
expect(result).toStrictEqual([expected]);
|
|
});
|
|
});
|
|
|
|
describe('using operator DoesNotExist', () => {
|
|
it.each([
|
|
['!key'],
|
|
[' !key'],
|
|
['! key '],
|
|
[' ! key '],
|
|
])('should parse expression %p to selector %p', (expression) => {
|
|
const expected = {
|
|
key: 'key',
|
|
operator: 'DoesNotExist',
|
|
};
|
|
|
|
const result = parse(expression);
|
|
|
|
expect(result).toStrictEqual([expected]);
|
|
});
|
|
|
|
it.each([
|
|
['!some.prefix/key-bar_baz '],
|
|
['! some.prefix/key-bar_baz '],
|
|
[' ! some.prefix/key-bar_baz '],
|
|
])('should parse expression %p to selector %p using prefixes', (expression) => {
|
|
const expected = {
|
|
key: 'some.prefix/key-bar_baz',
|
|
operator: 'DoesNotExist',
|
|
};
|
|
|
|
const result = parse(expression);
|
|
|
|
expect(result).toStrictEqual([expected]);
|
|
});
|
|
});
|
|
|
|
it('should parse compound', () => {
|
|
const expression = `foo=bar,+bar notin ( baz,qux) ,
|
|
some.domain/key, environment IN (production, qa ) ,
|
|
! another.domain/no-key`;
|
|
const expected = [
|
|
{
|
|
key: 'foo',
|
|
operator: 'In',
|
|
values: ['bar']
|
|
},
|
|
{
|
|
key: 'bar',
|
|
operator: 'NotIn',
|
|
values: ['baz', 'qux']
|
|
},
|
|
{
|
|
key: 'some.domain/key',
|
|
operator: 'Exists'
|
|
},
|
|
{
|
|
key: 'environment',
|
|
operator: 'In',
|
|
values: ['production', 'qa']
|
|
},
|
|
{
|
|
key: 'another.domain/no-key',
|
|
operator: 'DoesNotExist'
|
|
},
|
|
];
|
|
|
|
const result = parse(expression);
|
|
|
|
expect(result).toStrictEqual(expected);
|
|
});
|
|
});
|
|
|
|
describe('fx: convertSelectorObj', () => {
|
|
});
|
|
|
|
describe('fx: convert', () => {
|
|
it('should convert labels to expression', () => {
|
|
const matchLabelsObj = {
|
|
foo: 'bar',
|
|
baz: 'bat',
|
|
};
|
|
const expected = [
|
|
{
|
|
key: 'foo',
|
|
operator: 'In',
|
|
values: ['bar']
|
|
},
|
|
{
|
|
key: 'baz',
|
|
operator: 'In',
|
|
values: ['bat']
|
|
},
|
|
];
|
|
|
|
const result = convert(matchLabelsObj);
|
|
|
|
expect(result).toStrictEqual(expected);
|
|
});
|
|
|
|
it('should prevent errors and return empty list if no parameter is provided', () => {
|
|
const result = convert();
|
|
|
|
expect(result).toStrictEqual([]);
|
|
expect(() => result).not.toThrow();
|
|
});
|
|
});
|
|
|
|
describe('fx: simplify', () => {
|
|
it('should convert simple expressions to labels', () => {
|
|
const input = [
|
|
{
|
|
key: 'foo',
|
|
operator: 'In',
|
|
values: ['bar']
|
|
},
|
|
{
|
|
key: 'baz',
|
|
operator: 'In',
|
|
values: ['bat']
|
|
},
|
|
];
|
|
const expected = {
|
|
matchLabels: {
|
|
foo: 'bar',
|
|
baz: 'bat',
|
|
},
|
|
matchExpressions: [],
|
|
};
|
|
|
|
const result = simplify(input);
|
|
|
|
expect(result).toStrictEqual(expected);
|
|
});
|
|
|
|
it('should preserve complex expressions', () => {
|
|
const expressions = [
|
|
{
|
|
key: 'baz',
|
|
operator: 'In',
|
|
values: ['bat', 'baz']
|
|
},
|
|
{
|
|
key: 'qux',
|
|
operator: 'Exists'
|
|
}
|
|
];
|
|
const input = [
|
|
{
|
|
key: 'foo',
|
|
operator: 'In',
|
|
values: ['bar']
|
|
},
|
|
...expressions
|
|
];
|
|
const expected = {
|
|
matchLabels: { foo: 'bar' },
|
|
matchExpressions: expressions,
|
|
};
|
|
|
|
const result = simplify(input);
|
|
|
|
expect(result).toStrictEqual(expected);
|
|
});
|
|
|
|
it('should preserve duplicate keys', () => {
|
|
const expressions = [
|
|
{
|
|
key: 'baz',
|
|
operator: 'In',
|
|
values: ['bat']
|
|
},
|
|
{
|
|
key: 'baz',
|
|
operator: 'In',
|
|
values: ['qux']
|
|
}
|
|
];
|
|
|
|
const input = [
|
|
{
|
|
key: 'foo',
|
|
operator: 'In',
|
|
values: ['bar']
|
|
},
|
|
...expressions
|
|
];
|
|
const expected = {
|
|
matchLabels: { foo: 'bar' },
|
|
matchExpressions: expressions,
|
|
};
|
|
|
|
const result = simplify(input);
|
|
|
|
expect(result).toStrictEqual(expected);
|
|
});
|
|
});
|
|
|
|
describe('fx: matches', () => {
|
|
const none = { metadata: { name: 'none', labels: {} } };
|
|
const a = { metadata: { name: 'a', labels: { a: '1' } } };
|
|
const b = { metadata: { name: 'b', labels: { b: '2' } } };
|
|
const ab = { metadata: { name: 'ab', labels: { a: '3', b: '4' } } };
|
|
|
|
it.each([
|
|
// Match Exists
|
|
['a', [a, ab]],
|
|
['b', [b, ab]],
|
|
['c', []],
|
|
|
|
// Match NotExists
|
|
['!a', [none, b]],
|
|
['!b', [none, a]],
|
|
['!c', [none, a, b, ab]],
|
|
|
|
// Match Equal
|
|
['a=1', [a]],
|
|
['a=2', []],
|
|
['a=3', [ab]],
|
|
|
|
['b==1', []],
|
|
['b==2', [b]],
|
|
['b==3', []],
|
|
['b==4', [ab]],
|
|
|
|
['c=1', []],
|
|
['c=2', []],
|
|
|
|
// Match Not Equal
|
|
['a!=1', [none, b, ab]],
|
|
['a!=2', [none, a, b, ab]],
|
|
['a!=3', [none, a, b]],
|
|
|
|
['b!=1', [none, a, b, ab]],
|
|
['b!=2', [none, a, ab]],
|
|
['b!=3', [none, a, b, ab]],
|
|
['b!=4', [none, a, b]],
|
|
|
|
['c!=1', [none, a, b, ab]],
|
|
['c!=2', [none, a, b, ab]],
|
|
|
|
// Match In
|
|
['a in (1,2)', [a]],
|
|
['a in (1,3)', [a, ab]],
|
|
['a in (2,3)', [ab]],
|
|
|
|
['b in (2,3)', [b]],
|
|
['b in (2,4)', [b, ab]],
|
|
['b in (3,4)', [ab]],
|
|
|
|
['c in (1,2,3,4)', []],
|
|
|
|
// Match Not In
|
|
['a notin (1,2)', [none, b, ab]],
|
|
['a notin (1,3)', [none, b]],
|
|
['a notin (2,3)', [none, a, b]],
|
|
|
|
['b notin (2,3)', [none, a, ab]],
|
|
['b notin (2,4)', [none, a]],
|
|
['b notin (3,4)', [none, a, b]],
|
|
|
|
['c notin (1,2,3,4)', [none, a, b, ab]],
|
|
|
|
// Match Gt
|
|
['a > 0', [a, ab]],
|
|
['a > 2', [ab]],
|
|
['a > 4', []],
|
|
|
|
// Match Lt
|
|
['a < 0', []],
|
|
['a < 2', [a]],
|
|
['a < 4', [a, ab]],
|
|
|
|
// Match matchLabels object
|
|
[{ a: '1' }, [a]],
|
|
|
|
// Match matchExpressions array
|
|
[
|
|
[{
|
|
key: 'a', operator: 'In', values: ['1']
|
|
}], [a]
|
|
],
|
|
|
|
// Handle garbage in
|
|
[42, []],
|
|
['a ~ 1', []],
|
|
])('should return matched condition if %p matches', (cond, expected) => {
|
|
const data = [none, a, b, ab];
|
|
const result = matching(data, cond);
|
|
|
|
expect(result).toStrictEqual(expected);
|
|
});
|
|
});
|
|
|
|
describe('fx: matching', () => {
|
|
});
|