Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unit tests for client.go #36

Merged
merged 21 commits into from
Jul 19, 2024
Merged

Add unit tests for client.go #36

merged 21 commits into from
Jul 19, 2024

Conversation

aulorbe
Copy link
Contributor

@aulorbe aulorbe commented Jul 9, 2024

Problem

We do not have unit tests for client.go. In an effort to work towards v1.0 readiness, we need them.

Solution

Add unit tests for key functions/methods in client.go, as outlined in this Asana ticket.

Add commands to Justfile to allow contributors to run unit tests or integration tests, if they don't want to run all tests with the usual just test cmd.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update
  • Infrastructure change (CI configs, etc)
  • Non-code change (docs, etc)
  • None of the above: (explain here)

Test Plan

CI passes.

justfile Outdated
set -o allexport
source .env
set +o allexport
go test -count=1 -v -run TestIntegrationClient ./pinecone
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This runs all tests that are methods on the ClientTestsIntegration object.

Copy link
Contributor Author

@aulorbe aulorbe Jul 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea here is that we can have separate structs for integration tests vs. unit tests. Right now, we only have one for integration tests, but we could have one for unit tests in the future. If we do that, we would change the test-unit command in the justfile to call whatever function we create that actually implements suite.Run(....), as we do here by calling TestIntegrationClient.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know you have another PR for adding tests to index connection as well - is there a way to just use "Integration" for this like the test-unit command? It feels like this will only run integration tests covered by TestIntegrationClient rather than any that include Integration.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right -- for some reason in my head there was a reason I did it differently for integration vs unit tests, but now I can't remember... and it doesn't seem to matter! I'll change :)

set -o allexport
source .env
set +o allexport
go test -v -run Unit ./pinecone
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This runs all tests that contain Unit in the title.

Copy link
Contributor Author

@aulorbe aulorbe Jul 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Strategy lifted from Subtests section of testing documentation here https://pkg.go.dev/testing#hdr-Subtests_and_Sub_benchmarks, which basically just uses a regex to run groups of tests.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(See this comment for more thoughts.)

@aulorbe aulorbe marked this pull request as ready for review July 15, 2024 17:45
@aulorbe aulorbe changed the title Add unit tests + differentiation for integration tests Add unit tests for client.go Jul 15, 2024
Copy link
Contributor

@austin-denoble austin-denoble left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! Thanks for splitting out integration and unit tests a bit better, plus adding all this coverage for various things.

Main comment of mine is how we're triggering tests in the justfile and whether that'll work for index_connection as well.

justfile Outdated
set -o allexport
source .env
set +o allexport
go test -count=1 -v -run TestIntegrationClient ./pinecone
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know you have another PR for adding tests to index connection as well - is there a way to just use "Integration" for this like the test-unit command? It feels like this will only run integration tests covered by TestIntegrationClient rather than any that include Integration.

@@ -11,14 +12,18 @@ import (
"strings"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/pinecone-io/go-pinecone/internal/gen/control"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: These imports seem unordered 🤔 did you run gofmt?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did! But I'll do it again :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[we spoke offline & this is actually correct; leaving as-is]

err int
expected *PineconeError
}{
{ // TODO: should really add a negative case here, but triggering a marshalling error is hard
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, what would a negative case be for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uhh idk , ignore this, apologies

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's no problem, was just curious

}, {
name: "Confirm http prefix is added",
url: "http://pinecone-api.io",
expected: "http://pinecone-api.io", // TODO: should this be https?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, it's expected that this should be http if they explicitly provided it. This is helpful for developing against something like Pinecone local.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks!

Comment on lines +1051 to +1054
// Save the current environment variable value and defer restoring it
originalHostEnv := os.Getenv("PINECONE_CONTROLLER_HOST")
defer os.Setenv("PINECONE_CONTROLLER_HOST", originalHostEnv)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right we can defer to do this. I should update some of the other tests...

Comment on lines +1094 to +1097
// Set environment variable for the test case
os.Setenv("PINECONE_CONTROLLER_HOST", tc.envHost)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this only be set if tc.envHost != ""?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no because then the 3rd test fails, since we set the env var "PINECONE_CONTROLLER_HOST" to whatever the value is of tc.envHost.

For the 3rd test, tc.envHost is equal to "". So then when we asserts that tc.expectedHost is equal to client.restClient.Server, it fails because "" is not equal to https://api.pinecone.io/

Copy link
Contributor

@austin-denoble austin-denoble left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

aulorbe added a commit that referenced this pull request Jul 19, 2024
## Problem

We do not have unit tests for the private functions inside
`index_connection.go`, as outlined in [this Asana
ticket](https://app.asana.com/0/1203260648987893/1207762835203548/f).

## Solution

Add 'em! 

Note: I've adjusted the `Justfile` and renamed the integration test
components in accordance with the strategy outlined in [this
PR](#36) (unit tests for
`client.go`).

## Type of Change

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [ ] This change requires a documentation update
- [ ] Infrastructure change (CI configs, etc)
- [x] Non-code change (docs, etc)
- [ ] None of the above: (explain here)

## Test Plan

CI passes.
aulorbe and others added 18 commits July 19, 2024 10:16
…efactor `Client.Index()`, bump `grpc` dep to 1.64.0 (#35)

We currently do not give users many options for configuring the
underlying `grpc.ClientConn` that's used by the `VectorServiceClient`
for interacting with the data plane. This will be important for allowing
configuration of things like timeouts and proxies, and also for allowing
us to unit test aspects of the data plane layer.

We have an open issue to allow more configuration of our gRPC
implementation: #13

I ended up implementing a few different things here. Ultimately, I feel
like these changes move us more in the right direction for allowing
configuration of our gRPC service for data plane operations.

I decided on leaving things a bit open-ended for the consumer. We give
them the option to pass variadic `grpc.DialOption` arguments when
calling `Client.Index(NewIndexConnParams{...})`. This makes providing
these options optional, and you can continue calling the function
without them as before.

If someone wants to configure the gRPC connection themselves, they have
some latitude to do that via the `Host` and `grpc.DialOption` helper
functions: https://pkg.go.dev/google.golang.org/[email protected]#DialOption.
However, since we're also applying some dial options of our own when
constructing the client, allowing this flexibility may require more care
when merging things in `newIndexConnection`. Specifically looking for
feedback on this if people have opinions. Being able to provide these
directly made it possible to unit test some of the behavior as well.

- Bump grpc version from `1.62.0` -> `1.64.0`. @aulorbe and I noticed
there was an issue with how we were calling `grpc.Dial()` for setting up
the `grpc.ClientConn`. If you passed in an invalid `host`, the `Dial`
operation would hang without error'ing for some period of time. I think
ultimately we should have been using `grpc.DialContext` to configure the
timeout, or using `grpc.WithTimeout()`. When looking at fixing this I
bumped our grpc dependency, and noticed the `Dial` and `DialContext`
methods are under deprecation notice - they want people using
`grpc.NewClient`. It felt like it made sense to go ahead and make this
change now:
  - `grpc.Dial` - https://pkg.go.dev/google.golang.org/[email protected]#Dial
- `grpc.NewClient` -
https://pkg.go.dev/google.golang.org/[email protected]#NewClient
- Refactor `Client` to have only one `Index` method add
`NewIndexConnParams` struct for passing to `Index` rather than discrete
arguments. It already felt like our functions for establishing an
`IndexConnection` were getting a bit bloated, and when I was looking at
adding in gRPC configuration options, it felt like we should go ahead
and update this before v1.0.0.
- Add unit test to validate metadata in outgoing RPC requests, and unit
tests to validate Client applies the appropriate values to
`IndexConnection` through `Client.Index`, `along with
Client.extractAuthHeader()`.
- Fix formatting in doc comment code blocks in both `client.go` and
`index_connection.go`.
- Bump `google.golang.org/grpc` to v1.65.0 to correct snyk security
vulnerability:
https://security.snyk.io/vuln/SNYK-GOLANG-GOOGLEGOLANGORGGRPCMETADATA-7430177

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [X] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [ ] This change requires a documentation update
- [ ] Infrastructure change (CI configs, etc)
- [ ] Non-code change (docs, etc)
- [ ] None of the above: (explain here)

Make sure CI for unit + integration tests is passing.

I've added unit tests to specifically target gRPC metadata, testing
passing a `grpc.DialOption`, and creating an `IndexConnection` via
`Client.Index()`.
@aulorbe aulorbe merged commit a3127fa into main Jul 19, 2024
3 checks passed
@aulorbe aulorbe deleted the Audrey/add-unit-tests branch July 19, 2024 17:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants