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 initial helloworld integration test #98

Merged

Conversation

bobcatfish
Copy link
Collaborator

@bobcatfish bobcatfish commented Oct 5, 2018

This is a WIP of adding an integration test to cover #59, which is a
simple TaskRun which has no inputs or outputs but just runs a container
that echoes helloworld.

At this point we have the logic to:

This also changes namespaces to be test specific, so each test can
create a namespace and tear it down, without needing to keep track of
resources created and delete them individually.

Also removes openAPIV3Schema validation:

When we were using kubebuilder, it generated openAPIV3schema validation
for us in our CRD declarations. However:

  1. No other knative projects use this
  2. Continuing to use this is forcing us to diverge from the other
    Knative projects, specifically I found that Status fields, although
    optional, were being required by the validation (as described at
    CRD validation doesn't accept empty values for type "object" fields kubernetes/apiextensions-apiserver#25), and
    the best way to work around it seemed to be to make them nullable (as
    per
    https://stackoverflow.com/questions/18088294/how-to-not-marshal-an-empty-struct-into-json-with-go)
    i.e. pointers, which is different from how Knative works, and
    introduces new problems (such as handling when these fields are null)
  3. We (or at least @pivotal-nader-ziada and @shashwathi for sure!) were
    maintaining these fiels manually :O

@knative-prow-robot
Copy link

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: bobcatfish

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@knative-prow-robot knative-prow-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Oct 5, 2018
@knative-prow-robot knative-prow-robot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Oct 5, 2018
Copy link
Member

@vdemeester vdemeester left a comment

Choose a reason for hiding this comment

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

input_resource_test.go needs some update 👼
Otherwise looks good 👍

Copy link
Member

@nader-ziada nader-ziada left a comment

Choose a reason for hiding this comment

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

you changed some types to pointers, so need to update the setup of the tests in input_resource_test.go

@@ -125,10 +124,9 @@ type TaskRun struct {
metav1.ObjectMeta `json:"metadata,omitempty"`

// +optional
Spec TaskRunSpec `json:"spec,omitempty"`
Spec *TaskRunSpec `json:"spec,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

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

why are we changing these to pointers?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

These became pointers b/c json marshalling will cause fields to be required, even if they are marked optional, unless they are nullable (https://stackoverflow.com/questions/18088294/how-to-not-marshal-an-empty-struct-into-json-with-go)

(Let me know if you know of a better way to handle this tho!)

Actually though, now that I think about it I don't know why the spec would be optional, so maybe I'll undo this change and make this required instead 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

looks like the spec is optional for all the knative/serving types too so maybe ill leave it as optional 🤔🤔🤔

// +optional
//TODO(aaron-prindle) change back to TaskRunStatus
Status buildv1alpha1.BuildStatus `json:"status,omitempty"`
Status *TaskRunStatus `json:"status,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

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

Also why pointer, in this example in serving its not used as a pointer to make sure its initialized to a value. Otherwise there will be no initial status and other checks could blow up

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Interesting! that's a good point, I'll try to dig a bit more and see what's going on

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think I got a bit confused about json + nullable fields and conflated the problems:

  1. If you mark a field as optional but it isn't nullable, it will still be present in generated json, but all the fields will be empty <-- this was unrelated to the problem I was seeing after all! 😅
  2. If the field is required but not present, it will be populated with default values; if the values inside this required field are not optional, then there is a problem b/c they have to be present, so in the serving example you linked the Status fields are all optional, same with Route

I think the real problem was that the fields in Status were required, so I'll make those optional instead.

Thanks for following up on this @pivotal-nader-ziada !!

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for fixing it

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Looking into it a bit more it seems the situation is actually slightly worse!

knative/serving isn't using openAPIV3Schema validation but we are ... it looks like this is why I'm running into errors even though this field is not required: kubernetes/apiextensions-apiserver#25

For now the best workaround I can think of is to make these pointers so they can be null - but I think I should open an issue to investigate this further :S

(Open to other ideas too!)

Copy link
Member

Choose a reason for hiding this comment

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

I think if serving isn't using openapi validation, we shouldn't either (build doesn't either). ISTR there were issues with getting it to work with our controllers, possible exactly the issues you're encountering now.

Copy link
Member

Choose a reason for hiding this comment

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

If it's annotation-based validation you're after, you might want knative/pkg#37

Personally I tend to prefer just writing code myself with tests, but 🤷‍♂️

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

okay discussed with @imjasonh and our current plan (can be changed tho!) is to REMOVE the openapi validation for now 😅 since:

  1. knative isn't using it and it seems like we have to diverge from serving to keep reasonably using it
  2. we have to update it by hand (which @pivotal-nader-ziada and @shashwathi have already been doing! thank you!!)

Copy link
Member

@nader-ziada nader-ziada Oct 5, 2018

Choose a reason for hiding this comment

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

consistency across Knative repos is better than doing it like we are now


pods := c.KubeClient.Kube.CoreV1().Pods(namespace)

fmt.Printf("I GOT PODS %s %s\n", podName, pods)
Copy link
Contributor

Choose a reason for hiding this comment

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

is there a mapping between build to pod? we can look for pods starting with expected name and error out if they don't

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yep! afaik in @aaron-prindle 's implementation, the names of the Builds are the same as the names of the TaskRuns. here we are using that to get the Build: b, err := c.BuildClient.Get(hwTaskRunName... (I'll add a comment about this), and then the Cluster is an attribute on Build which we can use to find the Pod - the next challenge is finding the right containers 😩

Copy link
Member

Choose a reason for hiding this comment

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

The build pods are terminated when the build is done

Copy link
Contributor

Choose a reason for hiding this comment

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

:(

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

hmm but even now it's possible to get logs from the pods the Build ran on, even if the Build has completed right? (is it the case that it's a race?)

Copy link
Member

Choose a reason for hiding this comment

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

You can’t get build logs after the build is done unless you have been saving them somewhere else

test/README.md Outdated

```go
var revisionName string
err := test.CheckConfigurationState(clients.ServingClient, configName, func(c *v1alpha1.Configuration) (bool, error) {
Copy link
Member

Choose a reason for hiding this comment

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

ConfigurationState doesn't belong in this repo

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

lol whoa whoops, totally didn't copy paste that in 😅

defer tearDown(logger, c.KubeClient, namespace)

// Create task
_, err := c.TaskClient.Create(getHelloWorldTask(namespace))
Copy link
Member

Choose a reason for hiding this comment

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

In the build repo I'm a total pain about preferring the form where it's clearer that err doesn't escape this scope so you don't have to think about whether it's referenced later:

if _, err := doStuff(); err != nil {
  // handle
}
// err isn't defined out here

I find it's helpful when reading to be able to mentally drop err from the list of things I care about.

When Go2 has better error handling these'll all just become check calls.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

kk ill try to use this when i can! thanks for the pointer. @tejal29 was pointing this out to me as well when we were pairing but i keep forgetting, plz let me know if you see me miss it again!

(The only thing I don't like is when this syntax sometimes forces you to declare var err error)

@bobcatfish
Copy link
Collaborator Author

input_resource_test.go needs some update 👼
you changed some types to pointers, so need to update the setup of the tests in input_resource_test.go

Nice, I didn't even realize we had these tests!! <3

@bobcatfish bobcatfish force-pushed the hello_world_integration_test branch from b1c2915 to bc80e37 Compare October 5, 2018 21:45
@knative-prow-robot knative-prow-robot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Oct 5, 2018
When we were using kubebuilder, it generated openAPIV3schema validation
for us in our CRD declarations. However:

1. No other knative projects use this
2. Continuing to use this is forcing us to diverge from the other
   Knative projects, specifically I found that `Status` fields, although
   optional, were being required by the validation (as described at
   kubernetes/apiextensions-apiserver#25), and
   the best way to work around it seemed to be to make them nullable (as
   per
   https://stackoverflow.com/questions/18088294/how-to-not-marshal-an-empty-struct-into-json-with-go)
   i.e. pointers, which is different from how Knative works, and
   introduces new problems (such as handling when these fields are null)
3. We (or at least @pivotal-nader-ziada and @shashwathi for sure!) were
   maintaining these fiels manually :O
@bobcatfish bobcatfish force-pushed the hello_world_integration_test branch 3 times, most recently from 1e2d24c to 34486c2 Compare October 5, 2018 22:00
Copy link
Contributor

@tejal29 tejal29 left a comment

Choose a reason for hiding this comment

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

/lgtm /hold


pods := c.KubeClient.Kube.CoreV1().Pods(namespace)

fmt.Printf("I GOT PODS %s %s\n", podName, pods)
Copy link
Contributor

Choose a reason for hiding this comment

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

:(

pods := c.KubeClient.Kube.CoreV1().Pods(namespace)
fmt.Printf("I GOT PODS %s %s\n", podName, pods)

// TODO: Verify logs from the pod, should output hello world
Copy link
Contributor

Choose a reason for hiding this comment

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

please remove commented out code. Lets add it back in, in next PR

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is a WIP of adding an integration test to cover #59, which is a
simple TaskRun which has no inputs or outputs but just runs a container
that echoes helloworld.

At this point we have the logic to:
- Create the Task and TaskRun
- Wait for the TaskRun to have a condition (TODO: actually check the
  conditions, waiting to rebase onto #86)
- Get the Build associated (not yet created, will be via #86)
- Get the Pod for the build
- TODO: get the logs for that Pod (we've been looking at
  https://github.com/knative/build/blob/e8c2cb6eb5cb09d9737ca9e6da4a1c68af3247b2/pkg/logs/logs.go#L36:6
  for inspiration)

This also changes namespaces to be test specific, so each test can
create a namespace and tear it down, without needing to keep track of
resources created and delete them individually.

Co-authored-by: Aaron Prindle <[email protected]>
@bobcatfish bobcatfish force-pushed the hello_world_integration_test branch from 34486c2 to ab3312a Compare October 5, 2018 22:05
@tejal29
Copy link
Contributor

tejal29 commented Oct 5, 2018

/lgtm

@knative-prow-robot knative-prow-robot added the lgtm Indicates that a PR is ready to be merged. label Oct 5, 2018
@knative-prow-robot knative-prow-robot merged commit e3f4ac4 into tektoncd:master Oct 5, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants