More tests and more nice diff.
This commit is contained in:
		
							parent
							
								
									e40abdb249
								
							
						
					
					
						commit
						1f3730b2b4
					
				|  | @ -12,6 +12,10 @@ Docker. | |||
| Docker | ||||
| Go | ||||
| 
 | ||||
| # Notice | ||||
| 
 | ||||
| The `manifest` folder in e2e tests folder is not commited to git, it comes from `/manifests` | ||||
| 
 | ||||
| ## Build test runner | ||||
| 
 | ||||
| In the directory of the cloned Postgres Operator repository change to the e2e | ||||
|  |  | |||
|  | @ -110,6 +110,14 @@ class EndToEndTestCase(unittest.TestCase): | |||
| 
 | ||||
|         k8s.wait_for_operator_pod_start() | ||||
| 
 | ||||
|         # make sure we start a new operator on every new run, | ||||
|         # this tackles the problem when kind is reused | ||||
|         # and the Docker image is infact changed (dirty one) | ||||
| 
 | ||||
|         # patch resync period, this can catch some problems with hanging e2e tests | ||||
|         # k8s.update_config({"data": {"resync_period":"30s"}},step="TestSuite setup") | ||||
|         k8s.update_config({}, step="TestSuite Startup") | ||||
| 
 | ||||
|         actual_operator_image = k8s.api.core_v1.list_namespaced_pod( | ||||
|             'default', label_selector='name=postgres-operator').items[0].spec.containers[0].image | ||||
|         print("Tested operator image: {}".format(actual_operator_image))  # shows up after tests finish | ||||
|  | @ -454,8 +462,6 @@ class EndToEndTestCase(unittest.TestCase): | |||
|         Lower resource limits below configured minimum and let operator fix it | ||||
|         ''' | ||||
|         k8s = self.k8s | ||||
|         cluster_label = 'application=spilo,cluster-name=acid-minimal-cluster'     | ||||
|         _, failover_targets = k8s.get_pg_nodes(cluster_label) | ||||
| 
 | ||||
|         # configure minimum boundaries for CPU and memory limits | ||||
|         minCPULimit = '503m' | ||||
|  | @ -545,6 +551,7 @@ class EndToEndTestCase(unittest.TestCase): | |||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             self.assertTrue(len(failover_targets)>0, "No failover targets available") | ||||
|             for failover_target in failover_targets: | ||||
|                 k8s.api.core_v1.patch_node(failover_target, patch_readiness_label) | ||||
| 
 | ||||
|  |  | |||
|  | @ -18,12 +18,14 @@ import ( | |||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/apimachinery/pkg/labels" | ||||
| 
 | ||||
| 	"github.com/sirupsen/logrus" | ||||
| 	acidzalando "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do" | ||||
| 	acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" | ||||
| 	"github.com/zalando/postgres-operator/pkg/spec" | ||||
| 	"github.com/zalando/postgres-operator/pkg/util" | ||||
| 	"github.com/zalando/postgres-operator/pkg/util/constants" | ||||
| 	"github.com/zalando/postgres-operator/pkg/util/k8sutil" | ||||
| 	"github.com/zalando/postgres-operator/pkg/util/nicediff" | ||||
| 	"github.com/zalando/postgres-operator/pkg/util/retryutil" | ||||
| ) | ||||
| 
 | ||||
|  | @ -169,6 +171,20 @@ func (c *Cluster) logPDBChanges(old, new *policybeta1.PodDisruptionBudget, isUpd | |||
| 	c.logger.Debugf("diff\n%s\n", util.PrettyDiff(old.Spec, new.Spec)) | ||||
| } | ||||
| 
 | ||||
| func logNiceDiff(log *logrus.Entry, old, new interface{}) { | ||||
| 	o, erro := json.MarshalIndent(old, "", "  ") | ||||
| 	n, errn := json.MarshalIndent(new, "", "  ") | ||||
| 
 | ||||
| 	if erro != nil || errn != nil { | ||||
| 		panic("could not marschal API objects, should not happen") | ||||
| 	} | ||||
| 
 | ||||
| 	nice := nicediff.Diff(string(o), string(n), true) | ||||
| 	for _, s := range strings.Split(nice, "\n") { | ||||
| 		log.Debugf(s) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (c *Cluster) logStatefulSetChanges(old, new *appsv1.StatefulSet, isUpdate bool, reasons []string) { | ||||
| 	if isUpdate { | ||||
| 		c.logger.Infof("statefulset %q has been changed", util.NameFromMeta(old.ObjectMeta)) | ||||
|  | @ -180,7 +196,9 @@ func (c *Cluster) logStatefulSetChanges(old, new *appsv1.StatefulSet, isUpdate b | |||
| 	if !reflect.DeepEqual(old.Annotations, new.Annotations) { | ||||
| 		c.logger.Debugf("metadata.annotation diff\n%s\n", util.PrettyDiff(old.Annotations, new.Annotations)) | ||||
| 	} | ||||
| 	c.logger.Debugf("spec diff between old and new statefulsets: \n%s\n", util.PrettyDiff(old.Spec, new.Spec)) | ||||
| 
 | ||||
| 	c.logger.Debugf("Statefulset spec is different") | ||||
| 	logNiceDiff(c.logger, old.Spec, new.Spec) | ||||
| 
 | ||||
| 	if len(reasons) > 0 { | ||||
| 		for _, reason := range reasons { | ||||
|  |  | |||
|  | @ -0,0 +1,191 @@ | |||
| // Copyright 2013 Google Inc.  All rights reserved.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| // Package diff implements a linewise diff algorithm.
 | ||||
| package nicediff | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| // Chunk represents a piece of the diff.  A chunk will not have both added and
 | ||||
| // deleted lines.  Equal lines are always after any added or deleted lines.
 | ||||
| // A Chunk may or may not have any lines in it, especially for the first or last
 | ||||
| // chunk in a computation.
 | ||||
| type Chunk struct { | ||||
| 	Added   []string | ||||
| 	Deleted []string | ||||
| 	Equal   []string | ||||
| } | ||||
| 
 | ||||
| func (c *Chunk) empty() bool { | ||||
| 	return len(c.Added) == 0 && len(c.Deleted) == 0 && len(c.Equal) == 0 | ||||
| } | ||||
| 
 | ||||
| // Diff returns a string containing a line-by-line unified diff of the linewise
 | ||||
| // changes required to make A into B.  Each line is prefixed with '+', '-', or
 | ||||
| // ' ' to indicate if it should be added, removed, or is correct respectively.
 | ||||
| func Diff(A, B string, skipEqual bool) string { | ||||
| 	aLines := strings.Split(A, "\n") | ||||
| 	bLines := strings.Split(B, "\n") | ||||
| 	return Render(DiffChunks(aLines, bLines), skipEqual) | ||||
| } | ||||
| 
 | ||||
| // Render renders the slice of chunks into a representation that prefixes
 | ||||
| // the lines with '+', '-', or ' ' depending on whether the line was added,
 | ||||
| // removed, or equal (respectively).
 | ||||
| func Render(chunks []Chunk, skipEqual bool) string { | ||||
| 	buf := new(strings.Builder) | ||||
| 	for _, c := range chunks { | ||||
| 		for _, line := range c.Added { | ||||
| 			fmt.Fprintf(buf, "+%s\n", line) | ||||
| 		} | ||||
| 		for _, line := range c.Deleted { | ||||
| 			fmt.Fprintf(buf, "-%s\n", line) | ||||
| 		} | ||||
| 		if !skipEqual { | ||||
| 			for _, line := range c.Equal { | ||||
| 				fmt.Fprintf(buf, " %s\n", line) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return strings.TrimRight(buf.String(), "\n") | ||||
| } | ||||
| 
 | ||||
| // DiffChunks uses an O(D(N+M)) shortest-edit-script algorithm
 | ||||
| // to compute the edits required from A to B and returns the
 | ||||
| // edit chunks.
 | ||||
| func DiffChunks(a, b []string) []Chunk { | ||||
| 	// algorithm: http://www.xmailserver.org/diff2.pdf
 | ||||
| 
 | ||||
| 	// We'll need these quantities a lot.
 | ||||
| 	alen, blen := len(a), len(b) // M, N
 | ||||
| 
 | ||||
| 	// At most, it will require len(a) deletions and len(b) additions
 | ||||
| 	// to transform a into b.
 | ||||
| 	maxPath := alen + blen // MAX
 | ||||
| 	if maxPath == 0 { | ||||
| 		// degenerate case: two empty lists are the same
 | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Store the endpoint of the path for diagonals.
 | ||||
| 	// We store only the a index, because the b index on any diagonal
 | ||||
| 	// (which we know during the loop below) is aidx-diag.
 | ||||
| 	// endpoint[maxPath] represents the 0 diagonal.
 | ||||
| 	//
 | ||||
| 	// Stated differently:
 | ||||
| 	// endpoint[d] contains the aidx of a furthest reaching path in diagonal d
 | ||||
| 	endpoint := make([]int, 2*maxPath+1) // V
 | ||||
| 
 | ||||
| 	saved := make([][]int, 0, 8) // Vs
 | ||||
| 	save := func() { | ||||
| 		dup := make([]int, len(endpoint)) | ||||
| 		copy(dup, endpoint) | ||||
| 		saved = append(saved, dup) | ||||
| 	} | ||||
| 
 | ||||
| 	var editDistance int // D
 | ||||
| dLoop: | ||||
| 	for editDistance = 0; editDistance <= maxPath; editDistance++ { | ||||
| 		// The 0 diag(onal) represents equality of a and b.  Each diagonal to
 | ||||
| 		// the left is numbered one lower, to the right is one higher, from
 | ||||
| 		// -alen to +blen.  Negative diagonals favor differences from a,
 | ||||
| 		// positive diagonals favor differences from b.  The edit distance to a
 | ||||
| 		// diagonal d cannot be shorter than d itself.
 | ||||
| 		//
 | ||||
| 		// The iterations of this loop cover either odds or evens, but not both,
 | ||||
| 		// If odd indices are inputs, even indices are outputs and vice versa.
 | ||||
| 		for diag := -editDistance; diag <= editDistance; diag += 2 { // k
 | ||||
| 			var aidx int // x
 | ||||
| 			switch { | ||||
| 			case diag == -editDistance: | ||||
| 				// This is a new diagonal; copy from previous iter
 | ||||
| 				aidx = endpoint[maxPath-editDistance+1] + 0 | ||||
| 			case diag == editDistance: | ||||
| 				// This is a new diagonal; copy from previous iter
 | ||||
| 				aidx = endpoint[maxPath+editDistance-1] + 1 | ||||
| 			case endpoint[maxPath+diag+1] > endpoint[maxPath+diag-1]: | ||||
| 				// diagonal d+1 was farther along, so use that
 | ||||
| 				aidx = endpoint[maxPath+diag+1] + 0 | ||||
| 			default: | ||||
| 				// diagonal d-1 was farther (or the same), so use that
 | ||||
| 				aidx = endpoint[maxPath+diag-1] + 1 | ||||
| 			} | ||||
| 			// On diagonal d, we can compute bidx from aidx.
 | ||||
| 			bidx := aidx - diag // y
 | ||||
| 			// See how far we can go on this diagonal before we find a difference.
 | ||||
| 			for aidx < alen && bidx < blen && a[aidx] == b[bidx] { | ||||
| 				aidx++ | ||||
| 				bidx++ | ||||
| 			} | ||||
| 			// Store the end of the current edit chain.
 | ||||
| 			endpoint[maxPath+diag] = aidx | ||||
| 			// If we've found the end of both inputs, we're done!
 | ||||
| 			if aidx >= alen && bidx >= blen { | ||||
| 				save() // save the final path
 | ||||
| 				break dLoop | ||||
| 			} | ||||
| 		} | ||||
| 		save() // save the current path
 | ||||
| 	} | ||||
| 	if editDistance == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	chunks := make([]Chunk, editDistance+1) | ||||
| 
 | ||||
| 	x, y := alen, blen | ||||
| 	for d := editDistance; d > 0; d-- { | ||||
| 		endpoint := saved[d] | ||||
| 		diag := x - y | ||||
| 		insert := diag == -d || (diag != d && endpoint[maxPath+diag-1] < endpoint[maxPath+diag+1]) | ||||
| 
 | ||||
| 		x1 := endpoint[maxPath+diag] | ||||
| 		var x0, xM, kk int | ||||
| 		if insert { | ||||
| 			kk = diag + 1 | ||||
| 			x0 = endpoint[maxPath+kk] | ||||
| 			xM = x0 | ||||
| 		} else { | ||||
| 			kk = diag - 1 | ||||
| 			x0 = endpoint[maxPath+kk] | ||||
| 			xM = x0 + 1 | ||||
| 		} | ||||
| 		y0 := x0 - kk | ||||
| 
 | ||||
| 		var c Chunk | ||||
| 		if insert { | ||||
| 			c.Added = b[y0:][:1] | ||||
| 		} else { | ||||
| 			c.Deleted = a[x0:][:1] | ||||
| 		} | ||||
| 		if xM < x1 { | ||||
| 			c.Equal = a[xM:][:x1-xM] | ||||
| 		} | ||||
| 
 | ||||
| 		x, y = x0, y0 | ||||
| 		chunks[d] = c | ||||
| 	} | ||||
| 	if x > 0 { | ||||
| 		chunks[0].Equal = a[:x] | ||||
| 	} | ||||
| 	if chunks[0].empty() { | ||||
| 		chunks = chunks[1:] | ||||
| 	} | ||||
| 	if len(chunks) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return chunks | ||||
| } | ||||
|  | @ -180,3 +180,13 @@ func TestIsSmallerQuantity(t *testing.T) { | |||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| func TestNiceDiff(t *testing.T) { | ||||
| 	o := "a\nb\nc\n" | ||||
| 	n := "b\nd\n" | ||||
| 	d := nicediff.Diff(o, n, true) | ||||
| 	t.Log(d) | ||||
| 	// t.Errorf("Lets see output")
 | ||||
| } | ||||
| */ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue