Register
Login
Resources
Docs Blog Datasets Glossary Case Studies Tutorials & Webinars
Product
Data Engine LLMs Platform Enterprise
Pricing Explore
Connect to our Discord channel

common.test.ts 4.6 KB

You have to be logged in to leave a comment. Sign In
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  1. import { getEnvBool, getEnvString } from '../../../../src/envars';
  2. import {
  3. HARM_PLUGINS,
  4. LLAMA_GUARD_ENABLED_CATEGORIES,
  5. LLAMA_GUARD_REPLICATE_PROVIDER,
  6. } from '../../../../src/redteam/constants';
  7. import { GRADERS } from '../../../../src/redteam/graders';
  8. import {
  9. createTestCase,
  10. getHarmfulAssertions,
  11. } from '../../../../src/redteam/plugins/harmful/common';
  12. jest.mock('../../../../src/envars');
  13. describe('harmful plugin', () => {
  14. beforeEach(() => {
  15. jest.mocked(getEnvBool).mockReset();
  16. jest.mocked(getEnvString).mockReset();
  17. });
  18. describe('getHarmfulAssertions', () => {
  19. beforeEach(() => {
  20. jest.mocked(getEnvBool).mockReset();
  21. jest.mocked(getEnvString).mockReset();
  22. });
  23. it('should return basic assertion for privacy category', () => {
  24. const assertions = getHarmfulAssertions('harmful:privacy');
  25. expect(assertions).toEqual([
  26. { metric: 'Harmful', type: 'promptfoo:redteam:harmful:privacy' },
  27. ]);
  28. });
  29. it('should return basic assertion for non-privacy category', () => {
  30. const assertions = getHarmfulAssertions('harmful:intellectual-property');
  31. expect(assertions).toEqual([
  32. { metric: 'Harmful', type: 'promptfoo:redteam:harmful:intellectual-property' },
  33. ]);
  34. });
  35. it('should return only basic assertions when moderation is disabled', () => {
  36. jest.mocked(getEnvBool).mockImplementation((key) => {
  37. if (key === 'PROMPTFOO_DISABLE_REDTEAM_MODERATION') {
  38. return true;
  39. }
  40. return false;
  41. });
  42. jest.mocked(getEnvString).mockReturnValue('test-key');
  43. const assertions = getHarmfulAssertions('harmful:privacy');
  44. expect(assertions).toHaveLength(1);
  45. expect(assertions).not.toContainEqual(expect.objectContaining({ type: 'moderation' }));
  46. });
  47. it('should prioritize Replicate over OpenAI when both keys are present', () => {
  48. jest.mocked(getEnvString).mockImplementation((key) => {
  49. if (key === 'REPLICATE_API_KEY') {
  50. return 'replicate-key';
  51. }
  52. if (key === 'OPENAI_API_KEY') {
  53. return 'openai-key';
  54. }
  55. return '';
  56. });
  57. const assertions = getHarmfulAssertions('harmful:privacy');
  58. expect(assertions).toContainEqual({
  59. metric: 'Harmful',
  60. type: 'moderation',
  61. value: LLAMA_GUARD_ENABLED_CATEGORIES,
  62. provider: LLAMA_GUARD_REPLICATE_PROVIDER,
  63. });
  64. expect(assertions).toHaveLength(2);
  65. });
  66. it('should handle REPLICATE_API_TOKEN', () => {
  67. jest.mocked(getEnvString).mockImplementation((key) => {
  68. if (key === 'REPLICATE_API_TOKEN') {
  69. return 'replicate-token';
  70. }
  71. return '';
  72. });
  73. const assertions = getHarmfulAssertions('harmful:privacy');
  74. expect(assertions).toContainEqual({
  75. metric: 'Harmful',
  76. type: 'moderation',
  77. value: LLAMA_GUARD_ENABLED_CATEGORIES,
  78. provider: LLAMA_GUARD_REPLICATE_PROVIDER,
  79. });
  80. });
  81. });
  82. describe('createTestCase', () => {
  83. it('should create test case with single line output', () => {
  84. const testCase = createTestCase('inputVar', 'single line output', 'harmful:privacy');
  85. expect(testCase).toEqual({
  86. vars: {
  87. inputVar: 'single line output',
  88. },
  89. metadata: {
  90. harmCategory: HARM_PLUGINS['harmful:privacy'],
  91. pluginId: 'harmful:privacy',
  92. },
  93. assert: expect.any(Array),
  94. });
  95. });
  96. it('should handle multiline output', () => {
  97. const testCase = createTestCase(
  98. 'inputVar',
  99. 'first line\nsecond line\nthird line',
  100. 'harmful:privacy',
  101. );
  102. expect(testCase.vars?.inputVar).toBe('first line\nsecond line\nthird line');
  103. });
  104. it('should handle whitespace in output', () => {
  105. const testCase = createTestCase('inputVar', ' padded output ', 'harmful:privacy');
  106. expect(testCase.vars?.inputVar).toBe('padded output');
  107. });
  108. it('should use harm category as fallback when not in HARM_PLUGINS', () => {
  109. const unknownCategory = 'harmful:unknown' as keyof typeof HARM_PLUGINS;
  110. const testCase = createTestCase('inputVar', 'test output', unknownCategory);
  111. expect(testCase.metadata?.harmCategory).toBe(unknownCategory);
  112. });
  113. });
  114. describe('plugin category validation', () => {
  115. it('should have graders for all harmful categories', () => {
  116. const harmCategories = Object.keys(HARM_PLUGINS);
  117. const harmGraders = Object.keys(GRADERS).filter((key) =>
  118. key.startsWith('promptfoo:redteam:harmful:'),
  119. );
  120. expect(harmGraders.length).toBeGreaterThanOrEqual(harmCategories.length);
  121. });
  122. });
  123. });
Tip!

Press p or to see the previous file or, n or to see the next file

Comments

Loading...