Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace core_ai;
18
 
19
use core_ai\aiactions\generate_image;
20
use core_ai\aiactions\generate_text;
21
use core_ai\aiactions\summarise_text;
22
use core_ai\aiactions\explain_text;
23
use core_ai\aiactions\responses\response_generate_image;
24
 
25
/**
26
 * Test ai subsystem manager methods.
27
 *
28
 * @package    core_ai
29
 * @copyright  2024 Matt Porritt <matt.porritt@moodle.com>
30
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
31
 * @covers     \core_ai\manager
32
 */
33
final class manager_test extends \advanced_testcase {
34
    /**
35
     * Test get_ai_plugin_classname.
36
     */
37
    public function test_get_ai_plugin_classname(): void {
38
        $manager = \core\di::get(manager::class);
39
 
40
        // We're working with a private method here, so we need to use reflection.
41
        $method = new \ReflectionMethod($manager, 'get_ai_plugin_classname');
42
 
43
        // Test a provider plugin.
44
        $classname = $method->invoke($manager, 'aiprovider_fooai');
45
        $this->assertEquals('aiprovider_fooai\\provider', $classname);
46
 
47
        // Test a placement plugin.
48
        $classname = $method->invoke($manager, 'aiplacement_fooplacement');
49
        $this->assertEquals('aiplacement_fooplacement\\placement', $classname);
50
 
51
        // Test an invalid plugin.
52
        $this->expectException(\coding_exception::class);
53
        $this->expectExceptionMessage('Plugin name does not start with \'aiprovider_\' or \'aiplacement_\': bar');
54
        $method->invoke($manager, 'bar');
55
    }
56
 
57
    /**
58
     * Test get_supported_actions.
59
     */
60
    public function test_get_supported_actions(): void {
61
        $manager = \core\di::get(manager::class);
62
        $actions = $manager->get_supported_actions('aiprovider_openai');
63
 
64
        // Assert array keys match the expected actions.
65
        $this->assertEquals([
66
            generate_text::class,
67
            generate_image::class,
68
            summarise_text::class,
69
            explain_text::class,
70
        ], $actions);
71
    }
72
 
73
    /**
74
     * Test create_provider_instance method.
75
     */
76
    public function test_create_provider_instance(): void {
77
        $this->resetAfterTest();
78
        global $DB;
79
 
80
        // Create the provider instance.
81
        $manager = \core\di::get(\core_ai\manager::class);
82
        $config = ['data' => 'goeshere'];
83
        $provider = $manager->create_provider_instance(
84
            classname: '\aiprovider_openai\provider',
85
            name: 'dummy',
86
            config: $config,
87
        );
88
 
89
        $this->assertIsInt($provider->id);
90
        $this->assertFalse($provider->enabled);
91
        $this->assertEquals('goeshere', $provider->config['data']);
92
 
93
        // Check the record was written to the DB.
94
        $record = $DB->get_record('ai_providers', ['id' => $provider->id], '*', MUST_EXIST);
95
        $this->assertEquals($provider->id, $record->id);
96
    }
97
 
98
    /**
99
     * Test create_provider_instance non provider class.
100
     */
101
    public function test_create_provider_instance_non_provider_class(): void {
102
        $this->resetAfterTest();
103
 
104
        // Should throw an exception as the class is not a provider.
105
        $this->expectException(\coding_exception::class);
106
        $this->expectExceptionMessage(' Provider class not valid: ' . $this::class);
107
 
108
        // Create the provider instance.
109
        $manager = \core\di::get(\core_ai\manager::class);
110
        $manager->create_provider_instance(
111
            classname: $this::class,
112
            name: 'dummy',
113
        );
114
    }
115
 
116
    /**
117
     * Test get_provider_record method
118
     */
119
    public function test_get_provider_record(): void {
120
        global $DB;
121
 
122
        $this->resetAfterTest();
123
 
124
        // Create a dummy provider record directly in the database.
125
        $config = ['data' => 'goeshere'];
126
        $record = new \stdClass();
127
        $record->name = 'dummy1';
128
        $record->provider = 'dummy';
129
        $record->enabled = 1;
130
        $record->config = json_encode($config);
131
        $record->actionconfig = json_encode(['generate_text' => 1]);
132
        $record->id = $DB->insert_record('ai_providers', $record);
133
 
134
        $manager = \core\di::get(\core_ai\manager::class);
135
        $provider = $manager->get_provider_record(['provider' => 'dummy']);
136
 
137
        $this->assertEquals($record->id, $provider->id);
138
    }
139
 
140
    /**
141
     * Test get_provider_records method.
142
     */
143
    public function test_get_provider_records(): void {
144
        $this->resetAfterTest();
145
        global $DB;
146
 
147
        // Create some dummy provider records directly in the database.
148
        $config = ['data' => 'goeshere'];
149
        $record1 = new \stdClass();
150
        $record1->name = 'dummy1';
151
        $record1->provider = 'dummy';
152
        $record1->enabled = 1;
153
        $record1->config = json_encode($config);
154
        $record1->actionconfig = json_encode(['generate_text' => 1]);
155
 
156
        $record2 = new \stdClass();
157
        $record2->name = 'dummy2';
158
        $record2->provider = 'dummy';
159
        $record2->enabled = 1;
160
        $record2->config = json_encode($config);
161
        $record2->actionconfig = json_encode(['generate_text' => 1]);
162
 
163
        $DB->insert_records('ai_providers', [
164
                $record1,
165
                $record2,
166
        ]);
167
 
168
        // Get the provider records.
169
        $manager = \core\di::get(\core_ai\manager::class);
170
        $providers = $manager->get_provider_records(['provider' => 'dummy']);
171
 
172
        // Assert that the records were returned.
173
        $this->assertCount(2, $providers);
174
    }
175
 
176
    /**
177
     * Test get_provider_instances method.
178
     */
179
    public function test_get_provider_instances(): void {
180
        $this->resetAfterTest();
181
        global $DB;
182
 
183
        $manager = \core\di::get(\core_ai\manager::class);
184
        $config = ['data' => 'goeshere'];
185
 
186
        $provider = $manager->create_provider_instance(
187
                classname: '\aiprovider_openai\provider',
188
                name: 'dummy',
189
                config: $config,
190
        );
191
 
192
        // Create an instance record for a non provider class.
193
        $record = new \stdClass();
194
        $record->name = 'dummy';
195
        $record->provider = 'dummy';
196
        $record->enabled = 1;
197
        $record->config = json_encode($config);
198
 
199
        $DB->insert_record('ai_providers', $record);
200
 
201
        // Get the provider instances.
202
        $instances = $manager->get_provider_instances();
203
        $this->assertDebuggingCalled('Unable to find a provider class for dummy');
204
        $this->assertCount(1, $instances);
205
        $this->assertEquals($provider->id, $instances[$provider->id]->id);
206
    }
207
 
208
    /**
209
     * Test update_provider_instance method.
210
     */
211
    public function test_update_provider_instance(): void {
212
        $this->resetAfterTest();
213
        global $DB;
214
 
215
        // Create the provider instance.
216
        $manager = \core\di::get(\core_ai\manager::class);
217
        $config = ['data' => 'goeshere'];
218
        $provider = $manager->create_provider_instance(
219
                classname: '\aiprovider_openai\provider',
220
                name: 'dummy',
221
                config: $config,
222
        );
223
 
224
        // Update the provider instance.
225
        $config['data'] = 'updateddata';
226
        $manager->update_provider_instance($provider, $config);
227
 
228
        // Check the record was updated in the DB.
229
        $record = $DB->get_record('ai_providers', ['id' => $provider->id], '*', MUST_EXIST);
230
        $this->assertEquals($provider->id, $record->id);
231
        $this->assertEquals('updateddata', json_decode($record->config)->data);
232
    }
233
 
234
    /**
235
     * Test delete_provider_instance method.
236
     */
237
    public function test_delete_provider_instance(): void {
238
        $this->resetAfterTest();
239
        global $DB;
240
 
241
        // Create the provider instance.
242
        $manager = \core\di::get(\core_ai\manager::class);
243
        $config = ['data' => 'goeshere'];
244
        $provider = $manager->create_provider_instance(
245
                classname: '\aiprovider_openai\provider',
246
                name: 'dummy',
247
                config: $config,
248
        );
249
 
250
        // Delete the provider instance.
251
        $manager->delete_provider_instance($provider);
252
 
253
        // Check the record was deleted from the DB.
254
        $record = $DB->record_exists('ai_providers', ['id' => $provider->id]);
255
        $this->assertFalse($record);
256
    }
257
 
258
    /**
259
     * Test get_providers_for_actions.
260
     */
261
    public function test_get_providers_for_actions(): void {
262
        $this->resetAfterTest();
263
        $manager = \core\di::get(manager::class);
264
        $actions = [
265
            generate_text::class,
266
            summarise_text::class,
267
            explain_text::class,
268
        ];
269
 
270
        // Create two provider instances.
271
        $config = [
272
            'apikey' => 'goeshere',
273
            'endpoint' => 'https://example.com',
274
        ];
275
        $provider1 = $manager->create_provider_instance(
276
            classname: '\aiprovider_openai\provider',
277
            name: 'dummy1',
278
            enabled: true,
279
            config: $config,
280
        );
281
 
282
        $config['apiendpoint'] = 'https://example.com';
283
        $provider2 = $manager->create_provider_instance(
284
            classname: '\aiprovider_azureai\provider',
285
            name: 'dummy2',
286
            enabled: true,
287
            config: $config,
288
        );
289
 
290
        // Get the providers for the actions.
291
        $providers = $manager->get_providers_for_actions($actions);
292
 
293
        // Assert that the providers array is indexed by action name.
294
        $this->assertEquals($actions, array_keys($providers));
295
 
296
        // Assert that there is only one provider for each action.
297
        $this->assertCount(2, $providers[generate_text::class]);
298
        $this->assertCount(2, $providers[summarise_text::class]);
299
        $this->assertCount(2, $providers[explain_text::class]);
300
 
301
        // Disable the generate text action for the Open AI provider.
302
        $setresult = $manager->set_action_state(
303
                plugin: $provider1->provider,
304
                actionbasename: generate_text::class::get_basename(),
305
                enabled: 0,
306
                instanceid: $provider1->id);
307
        // Assert that the action was disabled.
308
        $this->assertFalse($setresult);
309
 
310
        $providers = $manager->get_providers_for_actions($actions, true);
311
 
312
        // Assert that there is no provider for the generate text action.
313
        $this->assertCount(1, $providers[generate_text::class]);
314
        $this->assertCount(2, $providers[summarise_text::class]);
315
 
316
        // Ordering the provider instances.
317
        // Re-enable the generate text action for the Openai provider.
318
        $manager->set_action_state(
319
            plugin: $provider1->provider,
320
            actionbasename: generate_text::class::get_basename(),
321
            enabled: 1,
322
            instanceid: $provider1->id,
323
        );
324
 
325
        // Move the $provider2 to the first provider for the generate text action.
326
        $manager->change_provider_order($provider2->id, \core\plugininfo\aiprovider::MOVE_UP);
327
        // Get the new providers for the actions.
328
        $providers = $manager->get_providers_for_actions($actions);
329
        // Assert whether provider2 is the first provider and provider1 is the last provider for the generate text action.
330
        $this->assertEquals($providers[generate_text::class][0], $provider2);
331
        $this->assertEquals($providers[generate_text::class][1], $provider1);
332
 
333
        // Move the $provider2 to the last provider for the generate text action.
334
        $manager->change_provider_order($provider2->id, \core\plugininfo\aiprovider::MOVE_DOWN);
335
        // Get the new providers for the actions.
336
        $providers = $manager->get_providers_for_actions($actions);
337
        // Assert whether provider1 is the first provider and provider2 is the last provider for the generate text action.
338
        $this->assertEquals($providers[generate_text::class][0], $provider1);
339
        $this->assertEquals($providers[generate_text::class][1], $provider2);
340
    }
341
 
342
    /**
343
     * Test process_action fail.
344
     */
345
    public function test_process_action_fail(): void {
346
        $this->resetAfterTest();
347
        global $DB;
348
        $managermock = $this->getMockBuilder(manager::class)
349
            ->setConstructorArgs([$DB])
350
            ->onlyMethods(['call_action_provider'])
351
            ->getMock();
352
 
353
        $expectedresult = new aiactions\responses\response_generate_image(
354
            success: true,
355
        );
356
 
357
        // Set up the expectation for call_action_provider to return the defined result.
358
        $managermock->expects($this->any())
359
            ->method('call_action_provider')
360
            ->willReturn($expectedresult);
361
 
362
        $action = new generate_image(
363
            contextid: 1,
364
            userid: 1,
365
            prompttext: 'This is a test prompt',
366
            quality: 'hd',
367
            aspectratio: 'square',
368
            numimages: 1,
369
            style: 'vivid',
370
        );
371
 
372
        // Success should be false as there are no enabled providers.
373
        $result = $managermock->process_action($action);
374
        $this->assertFalse($result->get_success());
375
    }
376
 
377
    /**
378
     * Test process_action.
379
     */
380
    public function test_process_action(): void {
381
        $this->resetAfterTest();
382
        global $DB;
383
 
384
        // Create two provider instances.
385
        $manager = \core\di::get(manager::class);
386
        $config = ['apikey' => 'goeshere'];
387
        $provider1 = $manager->create_provider_instance(
388
                classname: '\aiprovider_openai\provider',
389
                name: 'dummy1',
390
                enabled: true,
391
                config: $config,
392
        );
393
 
394
        $config['apiendpoint'] = 'https://example.com';
395
        $provider2 = $manager->create_provider_instance(
396
                classname: '\aiprovider_azureai\provider',
397
                name: 'dummy2',
398
                enabled: true,
399
                config: $config,
400
        );
401
 
402
        $managermock = $this->getMockBuilder(manager::class)
403
            ->setConstructorArgs([$DB])
404
            ->onlyMethods(['call_action_provider'])
405
            ->getMock();
406
 
407
        $expectedresult = new aiactions\responses\response_generate_image(
408
            success: true,
409
        );
410
 
411
        // Set up the expectation for call_action_provider to return the defined result.
412
        $managermock->expects($this->any())
413
            ->method('call_action_provider')
414
            ->willReturn($expectedresult);
415
 
416
        $action = new generate_image(
417
            contextid: 1,
418
            userid: 1,
419
            prompttext: 'This is a test prompt',
420
            quality: 'hd',
421
            aspectratio: 'square',
422
            numimages: 1,
423
            style: 'vivid',
424
        );
425
 
426
        // Should now return the expected result.
427
        $result = $managermock->process_action($action);
428
        $this->assertEquals($expectedresult, $result);
429
    }
430
 
431
    /**
432
     * Test set_user_policy.
433
     */
434
    public function test_set_user_policy(): void {
435
        $this->resetAfterTest();
436
        global $DB;
437
 
438
        $result = manager::user_policy_accepted(1, 1);
439
        $this->assertTrue($result);
440
 
441
        // Check record exists.
442
        $record = $DB->record_exists('ai_policy_register', ['userid' => 1, 'contextid' => 1]);
443
        $this->assertTrue($record);
444
    }
445
 
446
    /**
447
     * Test get_user_policy.
448
     */
449
    public function test_get_user_policy(): void {
450
        $this->resetAfterTest();
451
        global $DB;
452
 
453
        // Should be false for user initially.
454
        $result = manager::get_user_policy_status(1);
455
        $this->assertFalse($result);
456
 
457
        // Manually add record to the database.
458
        $record = new \stdClass();
459
        $record->userid = 1;
460
        $record->contextid = 1;
461
        $record->timeaccepted = time();
462
 
463
        $DB->insert_record('ai_policy_register', $record);
464
 
465
        // Should be true for user now.
466
        $result = manager::get_user_policy_status(1);
467
        $this->assertTrue($result);
468
    }
469
 
470
    /**
471
     * Test policy cache data source.
472
     */
473
    public function test_user_policy_caching(): void {
474
        global $DB;
475
        $this->resetAfterTest();
476
 
477
        $user1 = $this->getDataGenerator()->create_user();
478
        $user2 = $this->getDataGenerator()->create_user();
479
        $user3 = $this->getDataGenerator()->create_user();
480
 
481
        // Manually add records to the database.
482
        $record1 = new \stdClass();
483
        $record1->userid = $user1->id;
484
        $record1->contextid = 1;
485
        $record1->timeaccepted = time();
486
 
487
        $record2 = new \stdClass();
488
        $record2->userid = $user2->id;
489
        $record2->contextid = 1;
490
        $record2->timeaccepted = time();
491
 
492
        $DB->insert_records('ai_policy_register', [
493
            $record1,
494
            $record2,
495
        ]);
496
 
497
        $policycache = \cache::make('core', 'ai_policy');
498
 
499
        // Test single user.
500
        $this->assertFalse($policycache->has($user1->id));
501
        $this->assertFalse($policycache->has($user2->id));
502
        $this->assertFalse($policycache->has($user3->id));
503
 
504
        $result = $policycache->get($user1->id);
505
        $this->assertTrue($result);
506
        $result = $policycache->get($user2->id);
507
        $this->assertTrue($result);
508
        $result = $policycache->get($user3->id);
509
        $this->assertFalse($result);
510
 
511
        $this->assertTrue($policycache->has($user1->id));
512
        $this->assertTrue($policycache->has($user2->id));
513
 
514
        // Purge the cache.
515
        $policycache->purge();
516
 
517
        // Test multiple users.
518
        $this->assertFalse($policycache->has($user1->id));
519
        $this->assertFalse($policycache->has($user2->id));
520
        $this->assertFalse($policycache->has($user3->id));
521
 
522
        $result = $policycache->get_many([$user1->id, $user2->id, $user3->id]);
523
        $this->assertNotEmpty($policycache->get_many($result));
524
        $this->assertTrue($result[$user1->id]);
525
        $this->assertTrue($result[$user2->id]);
526
        $this->assertFalse($result[$user3->id]);
527
 
528
        $this->assertTrue($policycache->has($user1->id));
529
        $this->assertTrue($policycache->has($user2->id));
530
    }
531
 
532
    /**
533
     * Test store_action_result.
534
     */
535
    public function test_store_action_result(): void {
536
        $this->resetAfterTest();
537
        global $DB;
538
 
539
        $contextid = 1;
540
        $userid = 1;
541
        $prompttext = 'This is a test prompt';
542
        $aspectratio = 'square';
543
        $quality = 'hd';
544
        $numimages = 1;
545
        $style = 'vivid';
546
 
547
        $action = new generate_image(
548
            contextid: 1,
549
            userid: $userid,
550
            prompttext: $prompttext,
551
            quality: $quality,
552
            aspectratio: $aspectratio,
553
            numimages: $numimages,
554
            style: $style
555
        );
556
 
557
        $body = [
558
            'revisedprompt' => 'This is a revised prompt',
559
            'imageurl' => 'https://example.com/image.png',
560
            'model' => 'dall-e-3',
561
        ];
562
        $actionresponse = new response_generate_image(
563
            success: true,
564
        );
565
        $actionresponse->set_response_data($body);
566
 
567
        $manager = \core\di::get(manager::class);
568
        $config = ['data' => 'goeshere'];
569
        $provider = $manager->create_provider_instance(
570
                classname: '\aiprovider_openai\provider',
571
                name: 'dummy',
572
                config: $config,
573
        );
574
 
575
        // We're working with a private method here, so we need to use reflection.
576
        $method = new \ReflectionMethod($manager, 'store_action_result');
577
        $storeresult = $method->invoke($manager, $provider, $action, $actionresponse);
578
 
579
        // Check the record was written to the DB with expected values.
580
        $record = $DB->get_record('ai_action_register', ['id' => $storeresult], '*', MUST_EXIST);
581
        $this->assertEquals($action->get_basename(), $record->actionname);
582
        $this->assertEquals($userid, $record->userid);
583
        $this->assertEquals($contextid, $record->contextid);
584
        $this->assertEquals($provider->get_name(), $record->provider);
585
        $this->assertEquals($actionresponse->get_errorcode(), $record->errorcode);
586
        $this->assertEquals($actionresponse->get_errormessage(), $record->errormessage);
587
        $this->assertEquals($action->get_configuration('timecreated'), $record->timecreated);
588
        $this->assertEquals($actionresponse->get_timecreated(), $record->timecompleted);
589
        $this->assertEquals($actionresponse->get_model_used(), $record->model);
590
    }
591
 
592
    /**
593
     * Test call_action_provider.
594
     */
595
    public function test_call_action_provider(): void {
596
        $this->resetAfterTest();
597
        $contextid = 1;
598
        $userid = 1;
599
        $prompttext = 'This is a test prompt';
600
        $aspectratio = 'square';
601
        $quality = 'hd';
602
        $numimages = 1;
603
        $style = 'vivid';
604
 
605
        $action = new generate_image(
606
            contextid: $contextid,
607
            userid: $userid,
608
            prompttext: $prompttext,
609
            quality: $quality,
610
            aspectratio: $aspectratio,
611
            numimages: $numimages,
612
            style: $style
613
        );
614
 
615
        $manager = \core\di::get(manager::class);
616
        $config = ['apikey' => 'goeshere'];
617
        $provider = $manager->create_provider_instance(
618
                classname: '\aiprovider_openai\provider',
619
                name: 'dummy',
620
                config: $config,
621
        );
622
 
623
        // We're working with a private method here, so we need to use reflection.
624
        $method = new \ReflectionMethod($manager, 'call_action_provider');
625
        $actionresult = $method->invoke($manager, $provider, $action);
626
 
627
        // Assert the result was of the correct type.
628
        $this->assertInstanceOf(response_generate_image::class, $actionresult);
629
    }
630
 
631
    /**
632
     * Test is_action enabled.
633
     */
634
    public function test_is_action_enabled(): void {
635
        $this->resetAfterTest();
636
        $action = generate_image::class;
637
        $manager = \core\di::get(manager::class);
638
 
639
        $config = ['apikey' => 'goeshere'];
640
        $provider = $manager->create_provider_instance(
641
            classname: '\aiprovider_openai\provider',
642
            name: 'dummy',
643
            config: $config,
644
        );
645
 
646
        // Should be enabled by default.
647
        $result = $manager->is_action_enabled(
648
            plugin: $provider->provider,
649
            actionclass: $action,
650
            instanceid: $provider->id
651
        );
652
        $this->assertTrue($result);
653
 
654
        // Disable the action.
655
        $manager->set_action_state(
656
            plugin: $provider->provider,
657
            actionbasename: $action::get_basename(),
658
            enabled: 0,
659
            instanceid: $provider->id
660
        );
661
 
662
        // Should now be disabled.
663
        $result = $manager->is_action_enabled(
664
            plugin: $provider->provider,
665
            actionclass: $action,
666
            instanceid: $provider->id
667
        );
668
        $this->assertFalse($result);
669
    }
670
 
671
    /**
672
     * Test enable_action.
673
     */
674
    public function test_enable_action(): void {
675
        $this->resetAfterTest();
676
        $action = generate_image::class;
677
 
678
        $manager = \core\di::get(manager::class);
679
 
680
        $config = ['apikey' => 'goeshere'];
681
        $provider = $manager->create_provider_instance(
682
                classname: '\aiprovider_openai\provider',
683
                name: 'dummy',
684
                config: $config,
685
        );
686
 
687
        // Disable the action.
688
        $setresult = $manager->set_action_state(
689
                plugin: $provider->provider,
690
                actionbasename: $action::get_basename(),
691
                enabled: 0,
692
                instanceid: $provider->id);
693
 
694
        // Should now be disabled.
695
        $this->assertFalse($setresult);
696
        $result = $manager->is_action_enabled(
697
                plugin: $provider->provider,
698
                actionclass: $action,
699
                instanceid: $provider->id
700
        );
701
        $this->assertFalse($result);
702
 
703
        // Enable the action.
704
        $manager = \core\di::get(manager::class);
705
        $result = $manager->set_action_state(
706
                plugin: $provider->provider,
707
                actionbasename: generate_text::class::get_basename(),
708
                enabled: 1,
709
                instanceid: $provider->id);
710
        $this->assertTrue($result);
711
    }
712
 
713
    /**
714
     * Test is_action_available method.
715
     */
716
    public function test_is_action_available(): void {
717
        $this->resetAfterTest();
718
        $action = generate_image::class;
719
 
720
        // Plugin is disabled by default, action state should not matter. Everything should be false.
721
        $manager = \core\di::get(manager::class);
722
        $result = $manager->is_action_available($action);
723
        $this->assertFalse($result);
724
 
725
        // Create the provider instance, actions will be enabled by default when the plugin is enabled.
726
        $config = ['apikey' => 'goeshere'];
727
        $provider = $manager->create_provider_instance(
728
            classname: '\aiprovider_openai\provider',
729
            name: 'dummy',
730
            enabled: true,
731
            config: $config,
732
        );
733
 
734
        // Should now be available.
735
        $result = $manager->is_action_available($action);
736
        $this->assertTrue($result);
737
 
738
        // Disable the action.
739
        $manager->set_action_state(
740
                plugin: $provider->provider,
741
                actionbasename: $action::get_basename(),
742
                enabled: 0,
743
                instanceid: $provider->id);
744
 
745
        // Should now be unavailable.
746
        $result = $manager->is_action_available($action);
747
        $this->assertFalse($result);
748
    }
749
}