TestRouting validates that a request which originates with aibridged will be handled by coder/aibridge's handling logic in a provider-specific manner. We must validate that logic that pertains to coder/coder is exercised. aibridge will only handle certain routes; we don't need to test these exhausti
(t *testing.T)
| 708 | // (that's coder/aibridge's responsibility), but we do need to validate that it handles |
| 709 | // requests correctly. |
| 710 | func TestRouting(t *testing.T) { |
| 711 | t.Parallel() |
| 712 | |
| 713 | cases := []struct { |
| 714 | name string |
| 715 | path string |
| 716 | expectedStatus int |
| 717 | expectedHits int // Expected hits to the upstream server. |
| 718 | }{ |
| 719 | { |
| 720 | name: "unsupported", |
| 721 | path: "/this-route-does-not-exist", |
| 722 | expectedStatus: http.StatusNotFound, |
| 723 | expectedHits: 0, |
| 724 | }, |
| 725 | { |
| 726 | name: "openai chat completions", |
| 727 | path: "/openai/v1/chat/completions", |
| 728 | expectedStatus: http.StatusTeapot, // Nonsense status to indicate server was hit. |
| 729 | expectedHits: 1, |
| 730 | }, |
| 731 | { |
| 732 | name: "anthropic messages", |
| 733 | path: "/anthropic/v1/messages", |
| 734 | expectedStatus: http.StatusTeapot, // Nonsense status to indicate server was hit. |
| 735 | expectedHits: 1, |
| 736 | }, |
| 737 | } |
| 738 | |
| 739 | for _, tc := range cases { |
| 740 | t.Run(tc.name, func(t *testing.T) { |
| 741 | t.Parallel() |
| 742 | |
| 743 | // Setup mock upstream AI server. |
| 744 | upstreamSrv := &mockAIUpstreamServer{} |
| 745 | openaiSrv := httptest.NewServer(upstreamSrv) |
| 746 | antSrv := httptest.NewServer(upstreamSrv) |
| 747 | t.Cleanup(openaiSrv.Close) |
| 748 | t.Cleanup(antSrv.Close) |
| 749 | |
| 750 | // Setup. |
| 751 | logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true}) |
| 752 | ctrl := gomock.NewController(t) |
| 753 | client := mock.NewMockDRPCClient(ctrl) |
| 754 | |
| 755 | providers := []aibridge.Provider{ |
| 756 | aibridge.NewOpenAIProvider(aibridge.OpenAIConfig{BaseURL: openaiSrv.URL}), |
| 757 | aibridge.NewAnthropicProvider(aibridge.AnthropicConfig{BaseURL: antSrv.URL}, nil), |
| 758 | } |
| 759 | pool, err := aibridged.NewCachedBridgePool(aibridged.DefaultPoolOptions, providers, logger, nil, testTracer) |
| 760 | require.NoError(t, err) |
| 761 | conn := &mockDRPCConn{} |
| 762 | client.EXPECT().DRPCConn().AnyTimes().Return(conn) |
| 763 | |
| 764 | client.EXPECT().IsAuthorized(gomock.Any(), gomock.Any()).AnyTimes().Return(&proto.IsAuthorizedResponse{OwnerId: uuid.NewString()}, nil) |
| 765 | client.EXPECT().GetMCPServerConfigs(gomock.Any(), gomock.Any()).AnyTimes().Return(&proto.GetMCPServerConfigsResponse{}, nil) |
| 766 | // This is the only recording we really care about in this test. This is called before the provider-specific logic processes |
| 767 | // the incoming request, and anything beyond that is the responsibility of coder/aibridge to test. |
nothing calls this directly
no test coverage detected