Repository: nomic-ai/gpt4all
File: gpt4all-chat/tests/python/test_server_api.py (Python)

Code before:
            process.kill()
            raise
        process.send_signal(signal.SIGINT)
        if retcode := process.wait():
            raise CalledProcessError(retcode, process.args)


@pytest.fixture
def chat_server_with_model(chat_server_with_model_config: dict[str, str]) -> Iterator[None]:
    chat_executable = Path(os.environ['CHAT_EXECUTABLE']).absolute()
    with subprocess.Popen(chat_executable, env=chat_server_with_model_config) as process:
        try:
            yield
        except:
            process.kill()
            raise
        process.send_signal(signal.SIGINT)
        if retcode := process.wait():
            raise CalledProcessError(retcode, process.args)


def test_with_models_empty(chat_server: None) -> None:
    # non-sense endpoint
    with pytest.raises(HTTPError) as excinfo:
        request.get('foobarbaz', wait=True)
    assert excinfo.value.response.status_code == 404

    # empty model list
    response = request.get('models', wait=True)
    assert response == {'object': 'list', 'data': []}

    # empty model info
    response = request.get('models/foo', wait=True)
    assert response == {}

    # POST for model list
    with pytest.raises(HTTPError) as excinfo:
        response = request.post('models', data=None, wait=True)
    assert excinfo.value.response.status_code == 405

    # POST for model info
    with pytest.raises(HTTPError) as excinfo:
        response = request.post('models/foo', data=None, wait=True)
    assert excinfo.value.response.status_code == 405

    # GET for completions
    with pytest.raises(HTTPError) as excinfo:
        response = request.get('completions', wait=True)
    assert excinfo.value.response.status_code == 405

    # GET for chat completions

Review comment (suggestion):
For checks like this I would prefer to pass an argument like `raise=False` that disables the raise_for_status call, and returns a `resp.status_code, resp.json()` tuple (typed as `tuple[int, Any]`).

Also, it wouldn't hurt to test the response body, even for non-200 responses.

Code after:
def chat_server() -> Iterator[None]:
    with prepare_chat_server(model_copied=False) as config:
        yield from start_chat_server(config)


@pytest.fixture
def chat_server_with_model() -> Iterator[None]:
    with prepare_chat_server(model_copied=True) as config:
        yield from start_chat_server(config)


def test_with_models_empty(chat_server: None) -> None:
    # non-sense endpoint
    status_code, response = request.get('foobarbaz', wait=True, raise_for_status=False)
    assert status_code == 404
    assert response is None

    # empty model list
    response = request.get('models')
    assert response == {'object': 'list', 'data': []}

    # empty model info
    response = request.get('models/foo')
    assert response == {}

    # POST for model list
    status_code, response = request.post('models', data=None, raise_for_status=False)
    assert status_code == 405
    assert response == {'error': {
        'code': None,
        'message': 'Not allowed to POST on /v1/models. (HINT: Perhaps you meant to use a different HTTP method?)',
        'param': None,
        'type': 'invalid_request_error',
    }}

    # POST for model info
    status_code, response = request.post('models/foo', data=None, raise_for_status=False)
    assert status_code == 405
    assert response == {'error': {
        'code': None,
        'message': 'Not allowed to POST on /v1/models/*. (HINT: Perhaps you meant to use a different HTTP method?)',
        'param': None,
        'type': 'invalid_request_error',
    }}

    # GET for completions
    status_code, response = request.get('completions', raise_for_status=False)
    assert status_code == 405
    assert response == {'error': {
        'code': 'method_not_supported',
        'message': 'Only POST requests are accepted.',