-
Notifications
You must be signed in to change notification settings - Fork 3
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 E2E tests #32
Add E2E tests #32
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've left some questions.
Makefile
Outdated
verify-ci: install-tools ## Run code checks | ||
PKGS="${GOFILES}" GOFMT="gofmt" ./hack/verify-ci.sh | ||
.PHONY: test-e2e | ||
test-e2e: ## Run E2E tests. Requires working Kubernetes cluster and a Kubeconfig file. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be updated to use the run-e2e.sh
script.
A follow-up question: do we need to leave a note that this is potentially destructive operation and to be sure you're running it on the correct cluster?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A follow-up question: do we need to leave a note that this is potentially destructive operation and to be sure you're running it on the correct cluster?
note that your tests may be destructive. We can assume these people know what they're doing and get what they deserve.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a note and fixed the command.
test/e2e/e2e_test.go
Outdated
) | ||
|
||
// kubeconfigPath is path to the kubernetes configuration file. | ||
var kubeconfigPath = filepath.Join(os.Getenv("HOME"), "/.kube/config") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a better way for providing kubeconfigPath
? Maybe with an environment variable, or this is good enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a better way for providing kubeconfigPath? Maybe with an environment variable, or this is good enough?
We respect KUBECONFIG
in most (all?) kube binaries. I'd use that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great idea, updated the PR to use it.
test/e2e/e2e_test.go
Outdated
var kubeconfigPath = filepath.Join(os.Getenv("HOME"), "/.kube/config") | ||
|
||
// newKubeClient create new Kubernetes client instance based on kubeconfig file. | ||
func newKubeClient(kubeconfigPath string) (*kubernetes.Clientset, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it okay to leave those functions in this file, or should I create a new file such as util.go
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it okay to leave those functions in this file, or should I create a new file such as util.go?
don't create a "util" anything until absolutely necessary. Let's say 1000 lines. They generally become a bucket of stuff.
test/e2e/e2e_test.go
Outdated
return clientset.NewForConfig(config) | ||
} | ||
|
||
func replicasetName(etcdstorageName string) string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My idea was to have a helper functions for calculating names, instead of hardcoding them in test cases, to make potential changes easier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My idea was to have a helper functions for calculating names, instead of hardcoding them in test cases, to make potential changes easier.
I generally question the utility of one liners. Do you think it's likely we'll change our minds? How many places would we really have to update it? Should such a change be hard since we're changing external behavior?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think it's likely we'll change our minds?
I don't think we'll ever change those. Even if we do in some case, that would be just a few lines to update. Let's get rid of those functions.
test/e2e/e2e_test.go
Outdated
return fmt.Sprintf("etcd-%s", etcdstorageName) | ||
} | ||
|
||
func TestDeployEtcdStorage(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it okay to have all these checks in this function, or I should split them to multiple tests? In this function we're testing is the EtcdStorage instance deployed, and are all relevant resources deployed.
TODO: add godoc comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added godoc comment.
test/e2e/e2e_test.go
Outdated
} | ||
|
||
// Only continue if etcdStorage is expected to be valid. | ||
if tc.etcdStorageValid { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a problem here.
We have defined that EtcdStorages name length should be less than 59 characters (64 which is max for Services, -5 for etcd-
prefix). I added a test case for that, but, this is going to fail on Create
.
But that failure is expected, so I was not sure how to stop there. I added etcdStorageValid
bool, and if it is false, error on Create is going to be ignored, and we're not going to continue.
Is there a better way to mark test as passed, than this one? There is 'FailNow(), which fails, but I don't want fail
.
There is also SkipNow()
, but it marks test as skipped, and I was not sure do we want that.
test/e2e/e2e_test.go
Outdated
// Only continue if etcdStorage is expected to be valid. | ||
if tc.etcdStorageValid { | ||
// It takes some time for the ReplicaSet and Service to be created, so we need to poll. | ||
err = wait.Poll(500*time.Millisecond, wait.ForeverTestTimeout, func() (bool, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: check for error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
test/e2e/e2e_test.go
Outdated
t.Fatalf("expected replicaset '%s', but got: %v", tc.expectedReplicaSetName, err) | ||
} | ||
// Wait for pods to become ready. | ||
err = wait.Poll(500*time.Millisecond, wait.ForeverTestTimeout, func() (bool, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: check for error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
test/e2e/e2e_test.go
Outdated
} | ||
|
||
// Check is ReplicaSet deployed. | ||
rs, err := client.AppsV1().ReplicaSets("kube-apiserver-storage").Get(tc.expectedReplicaSetName, metav1.GetOptions{}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not needed, we have it in wait.Poll
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
.travis.yml
Outdated
script: make test-e2e | ||
before_script: | ||
# Download kubectl, which is a requirement for using minikube and running e2e tests. | ||
- curl -Lo kubectl https://storage.googleapis.com/kubernetes-release/release/${KUBERNETES_VERSION}/bin/linux/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I object 😝
.travis.yml
Outdated
# Update the kubeconfig to use the minikube cluster. | ||
- minikube update-context | ||
# Wait for Kubernetes to be up and ready. | ||
- JSONPATH='{range .items[*]}{@.metadata.name}:{range @.status.conditions[*]}{@.type}={@.status};{end}{end}'; until kubectl get nodes -o jsonpath="$JSONPATH" 2>&1 | grep -q "Ready=True"; do sleep 1; done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In addition, I'd suggest waiting for the server's /healthz to report true.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a TODO note. I'll try to get it for this PR.
test/e2e/e2e_test.go
Outdated
return kubernetes.NewForConfig(config) | ||
} | ||
|
||
func newEtcdProxyClinet(kubeconfigPath string) (*clientset.Clientset, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙈
test/e2e/e2e_test.go
Outdated
|
||
// newEtcdProxyClient creates new client for etcdstorage resources. | ||
func newEtcdProxyClient() (*clientset.Clientset, error) { | ||
config, err := clientcmd.BuildConfigFromFlags("", os.Getenv("KUBECONFIG")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would have one helper to create the config and then do the NewForConfig call inline. I also tolerate NewForConfigOrDie
in tests.
test/e2e/e2e_test.go
Outdated
etcdStorageValid: true, | ||
}, | ||
{ | ||
name: "test etcdstorage creation - name too long", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be a unit test
for _, tc := range tests { | ||
t.Run(tc.name, func(t *testing.T) { | ||
// Create an EtcdStorage instance. | ||
es, err := etcdproxyClient.EtcdV1alpha1().EtcdStorages().Create(tc.etcdStorage) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing deletion/cleanup
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
This is fine, but in general I expect my e2e tests to tell a story. In kube, they alias The ideal e2e test would be creating your sample manifests. If you want to simply create a bash script you call to do that for now, that would be fine, but I think it is important to do. |
467d4e3
to
d80f700
Compare
@deads2k I've addressed comments from yesterday and added an E2E story for the sample-apiserver. Compared to EtcdStorage story, which is using a Bash script + Go, the sample-apiserver story is only using the bash script. The tests for sample-apiserver are checking is the pod ready. This is probably not enough, but I don't have idea what else could I check. If you have some ideas, let me know. :) Also, I've disabled E2E tests in Travis as they're failing. The tests are passing locally, so for now, let's leave it off if you agree. |
READY_REPLICAS=$(kubectl get rs apiserver -o jsonpath="{.status.readyReplicas}") | ||
done | ||
|
||
echo '* Starting sample-apiserver e2e tests.' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
followup issue to actually create a resource.
// Initialize clients. | ||
cfg, err := clientcmd.BuildConfigFromFlags("", os.Getenv("KUBECONFIG")) | ||
if err != nil { | ||
t.Fatalf("unable to create kubernetes config from provided kubeconfig file: %v", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I generally just use t.Fatal(err). You get a line number, so you can track it back easily enough.
Yeah, that's fine. Don't forget to run your e2e and tell us in the description whether it worked or not. |
This PR adds E2E tests for the EtcdProxyController.
The E2E tests assumes you have a working Kubernetes cluster and EtcdProxy Controller deployed. The
hack/run-e2e.sh
script, which is used by CI, deploys the controller from the deployment manifest located in theartifacts
directory.By default, tests use the kubeconfig located in
$HOME/.kube/config
. The kubeconfig path can be changed by modifying thekubeconfigPath
variable in thetest/e2e/e2e_test.go
file.The tests are located in the
test/e2e/e2e_test.go
file. Currently, we have one test function which tests:We're testing two cases for now:
I'm also working on testing are all resources going to be deleted once the EtcdStorage object is deleted.