spec/tasks/setup_ai_gateway_spec.rb (140 lines of code) (raw):

# frozen_string_literal: true RSpec.describe 'rake setup_ai_gateway', :hide_output do let(:env_file) { AI_GATEWAY_ENV_FILE } let(:env_runit_file) { ENV_RUNIT_FILE } let(:log_file) { LOG_FILE } let(:gateway_enabled) { false } let(:raw_yaml) { "---\ngitlab_ai_gateway:\n enabled: #{gateway_enabled}\ngdk:\n root: /path/to/gdk" } before(:all) do Rake.application.rake_require('tasks/setup_ai_gateway') end before do stub_raw_gdk_yaml(raw_yaml) allow(GDK::Output).to receive(:prompt).and_return('test_input') allow(File).to receive_messages(write: nil, exist?: false, read: '', open: nil) allow(File).to receive(:file?).with(env_file.to_s).and_return(true) allow(GDK.config).to receive(:bury!).with('gitlab_ai_gateway.enabled', true) allow(GDK.config).to receive(:save_yaml!) allow_any_instance_of(GDK::Command::Update).to receive(:run).and_return(true) allow_any_instance_of(GDK::Command::Restart).to receive(:run) allow(GDK).to receive(:make).with('gitlab-ai-gateway-gcloud-setup') end context 'when running the task' do before do allow(GDK::Output).to receive(:prompt).with('Enter your Anthropic API key').and_return('test_api_key') allow(GDK::Output).to receive(:prompt) .with('Do you want to set additional environment variables for debugging? [y/N]') .and_return('y') allow(GDK::Output).to receive(:prompt) .with('Do you want to enable Duo Features in SaaS (GitLab.com) Mode? [y/N]') .and_return('y') allow(GDK::Output).to receive(:prompt) .with('Do you want to enable hot reload?[y/N]') .and_return('y') allow(File).to receive(:exist?).with(env_file.to_s).and_return(false) end it 'configures AI Gateway, updates environment, and restarts services' do expect(GDK.config).to receive(:bury!).with('gitlab_ai_gateway.enabled', true) expect(GDK.config).to receive(:save_yaml!) expect(File).to receive(:write).with(env_file.to_s, "ANTHROPIC_API_KEY=test_api_key\n").ordered expect(GDK).to receive(:make).with('gitlab-ai-gateway-gcloud-setup') expect(File).to receive(:write).with(env_file.to_s, "AIGW_LOGGING__LEVEL=debug\n") expect(File).to receive(:write).with(env_file.to_s, "AIGW_LOGGING__FORMAT_JSON=false\n") expect(File).to receive(:write).with( env_file.to_s, %r{AIGW_LOGGING__TO_FILE=.*/log/gitlab-ai-gateway/gateway_debug\.log\n} ) expect(File).to receive(:write).with(env_file.to_s, "AIGW_FASTAPI__RELOAD=true\n") expect(File).to receive(:open).with(env_runit_file.to_s, 'a') task.execute end end context 'when exporting env_runit variables' do let(:env_runit_contents) { '' } before do allow(GDK::Output).to receive(:prompt).with(/Do you want to enable Duo Features in SaaS \(GitLab\.com\) Mode?/).and_return('y') allow(File).to receive(:exist?).with(env_runit_file.to_s).and_return(true) allow(File).to receive(:read).with(env_runit_file.to_s).and_return(env_runit_contents) end shared_examples 'writes correct content' do |saas_input, expected_saas_value| before do allow(GDK::Output).to receive(:prompt).with(/Do you want to enable Duo Features in SaaS \(GitLab\.com\) Mode?/).and_return(saas_input) end it "writes correct content for saas_mode_enabled '#{saas_input}'" do allow(File).to receive(:open).with(env_runit_file.to_s, 'a') do |file| expect(file).to receive(:write).with("export GITLAB_SIMULATE_SAAS=#{expected_saas_value}\n") expect(file).to receive(:write).with("export AI_GATEWAY_URL=http://0.0.0.0:5052\n") end end end context 'when env_runit_contents is empty' do let(:env_runit_contents) { '' } it_behaves_like 'writes correct content', 'y', '1' it_behaves_like 'writes correct content', 'n', '0' end context 'when GITLAB_SIMULATE_SAAS is not present' do let(:env_runit_contents) { 'EXISTING_VAR=value\n' } it_behaves_like 'writes correct content', 'y', '1' it_behaves_like 'writes correct content', 'n', '0' end context 'when GITLAB_SIMULATE_SAAS is already present' do let(:env_runit_contents) { "export GITLAB_SIMULATE_SAAS=1\n" } it 'does not write GITLAB_SIMULATE_SAAS again' do expect(File).to receive(:open).with(env_runit_file.to_s, 'a') task.execute end end context 'when AI_GATEWAY_URL is already present' do let(:env_runit_contents) { "export AI_GATEWAY_URL=http://0.0.0.0:5052\n" } it 'writes GITLAB_SIMULATE_SAAS but not AI_GATEWAY_URL' do expect(File).to receive(:open).with(env_runit_file.to_s, 'a') task.execute end end context 'when both GITLAB_SIMULATE_SAAS and AI_GATEWAY_URL are present' do let(:env_runit_contents) { "export GITLAB_SIMULATE_SAAS=1\nexport AI_GATEWAY_URL=http://0.0.0.0:5052" } it 'does not write anything' do expect(File).not_to receive(:open).with(env_runit_file.to_s, 'a') expect(File).not_to receive(:write).with(env_runit_file.to_s, anything) task.execute end end end context 'when user declines debug variables and hot reload' do let(:gateway_enabled) { true } before do allow(GDK::Output).to receive(:prompt).with('Enter your Anthropic API key').and_return('test_api_key') allow(GDK::Output).to receive(:prompt).with(/Do you want to set additional environment variables for debugging?/) .and_return('n') allow(GDK::Output).to receive(:prompt).with('Do you want to enable hot reload?[y/N]').and_return('n') end it 'skips setting debug variables and enabling hot reload' do expect(File).not_to receive(:write).with(env_file.to_s, /AIGW_LOGGING__LEVEL=debug/) expect(File).not_to receive(:write).with(env_file.to_s, /AIGW_FASTAPI__RELOAD=true/) task.execute end end context 'when .env file already exists' do let(:existing_env_content) { "EXISTING_VAR=value\n" } let(:gateway_enabled) { true } before do allow(File).to receive(:exist?).with(env_file.to_s).and_return(true) allow(File).to receive(:read).with(env_file.to_s).and_return(existing_env_content) allow(GDK::Output).to receive(:prompt).with('Enter your Anthropic API key').and_return('test_api_key') end it 'updates existing ANTHROPIC_API_KEY if present' do allow(File).to receive(:read).with(env_file.to_s).and_return("ANTHROPIC_API_KEY=old_key\n") expect(File).to receive(:write).with(env_file.to_s, "ANTHROPIC_API_KEY=test_api_key\n") task.execute end it 'appends ANTHROPIC_API_KEY if not present' do expect(File).to receive(:write).with(env_file.to_s, "EXISTING_VAR=value\nANTHROPIC_API_KEY=test_api_key\n") task.execute end it 'handles frozen strings correctly' do frozen_content = "EXISTING_VAR=value\n" allow(File).to receive(:read).with(env_file.to_s).and_return(frozen_content) expect(File).to receive(:write).with(env_file.to_s, "EXISTING_VAR=value\nANTHROPIC_API_KEY=test_api_key\n") expect { task.execute }.not_to raise_error end end end