@@ -1814,3 +1814,134 @@ func BenchmarkMultipleApplierRecursiveRealConversion(b *testing.B) {
1814
1814
}
1815
1815
}
1816
1816
}
1817
+
1818
+ var multiversionWithReliantFieldsParser = func () Parser {
1819
+ parser , err := typed .NewParser (`types:
1820
+ - name: v1
1821
+ map:
1822
+ fields:
1823
+ - name: field_foo_rely_on_bar
1824
+ type:
1825
+ scalar: string
1826
+ - name: common_field
1827
+ type:
1828
+ scalar: string
1829
+ - name: v2
1830
+ map:
1831
+ fields:
1832
+ - name: required_field_bar
1833
+ type:
1834
+ scalar: string
1835
+ - name: common_field
1836
+ type:
1837
+ scalar: string
1838
+ ` )
1839
+ if err != nil {
1840
+ panic (err )
1841
+ }
1842
+ return parser
1843
+ }()
1844
+
1845
+ // reliantFieldsConverter converts v2 obj to v1 relying on the required_field_bar,
1846
+ // if required_field_bar is empty, the conversion shall fail.
1847
+ // This converter can only be used with multiversionWithReliantFieldsParser.
1848
+ type reliantFieldsConverter struct {
1849
+ }
1850
+
1851
+ var _ merge.Converter = reliantFieldsConverter {}
1852
+
1853
+ func (r reliantFieldsConverter ) Convert (v * typed.TypedValue , version fieldpath.APIVersion ) (* typed.TypedValue , error ) {
1854
+ inVersion := fieldpath .APIVersion (* v .TypeRef ().NamedType )
1855
+ if inVersion == version {
1856
+ return v , nil
1857
+ }
1858
+ y , err := yaml .Marshal (v .AsValue ().Unstructured ())
1859
+ if err != nil {
1860
+ return nil , err
1861
+ }
1862
+ inStr := string (y )
1863
+ var outStr string
1864
+ switch version {
1865
+ case "v1" :
1866
+ if ! strings .Contains (inStr , "required_field_bar" ) {
1867
+ return v , fmt .Errorf ("missing requried field bar" )
1868
+ }
1869
+ outStr = strings .Replace (inStr , "required_field_bar" , "field_foo_rely_on_bar" , - 1 )
1870
+ case "v2" :
1871
+ outStr = strings .Replace (inStr , "field_foo_rely_on_bar" , "required_field_bar" , - 1 )
1872
+ default :
1873
+ return nil , missingVersionError
1874
+ }
1875
+ return multiversionWithReliantFieldsParser .Type (string (version )).FromYAML (typed .YAMLObject (outStr ))
1876
+ }
1877
+
1878
+ func (r reliantFieldsConverter ) IsMissingVersionError (err error ) bool {
1879
+ return err == missingVersionError
1880
+ }
1881
+
1882
+ func TestMultipleAppliersReliantFieldsConversions (t * testing.T ) {
1883
+ tests := map [string ]TestCase {
1884
+ "multiple_versions_with_reliant_fields" : {
1885
+ Ops : []Operation {
1886
+ Apply {
1887
+ Manager : "v2_applier" ,
1888
+ APIVersion : "v2" ,
1889
+ Object : typed .YAMLObject (`
1890
+ required_field_bar: a
1891
+ ` ),
1892
+ },
1893
+ Apply {
1894
+ Manager : "v1_applier" ,
1895
+ APIVersion : "v1" ,
1896
+ Object : typed .YAMLObject (`
1897
+ common_field: b
1898
+ ` ),
1899
+ },
1900
+ Apply {
1901
+ Manager : "v2_applier" ,
1902
+ APIVersion : "v2" ,
1903
+ Object : typed .YAMLObject (`
1904
+ required_field_bar: b
1905
+ ` ),
1906
+ },
1907
+ },
1908
+ Object : typed .YAMLObject (`
1909
+ required_field_bar: b
1910
+ common_field: b
1911
+ ` ),
1912
+ APIVersion : "v2" ,
1913
+ Managed : fieldpath.ManagedFields {
1914
+ "v2_applier" : fieldpath .NewVersionedSet (
1915
+ _NS (
1916
+ _P ("required_field_bar" ),
1917
+ ),
1918
+ "v2" ,
1919
+ true ,
1920
+ ),
1921
+ "v1_applier" : fieldpath .NewVersionedSet (
1922
+ _NS (
1923
+ _P ("common_field" ),
1924
+ ),
1925
+ "v1" ,
1926
+ true ,
1927
+ ),
1928
+ },
1929
+ },
1930
+ }
1931
+
1932
+ converter := reliantFieldsConverter {}
1933
+ for name , test := range tests {
1934
+ t .Run (name , func (t * testing.T ) {
1935
+ runTimes := 1
1936
+ if name == "multiple_versions_with_reliant_fields" {
1937
+ // run this test for enough times to get as consistent results as possible
1938
+ runTimes = 100
1939
+ }
1940
+ for i := 0 ; i < runTimes ; i ++ {
1941
+ if err := test .TestWithConverter (multiversionWithReliantFieldsParser , converter ); err != nil {
1942
+ t .Fatal (err )
1943
+ }
1944
+ }
1945
+ })
1946
+ }
1947
+ }
0 commit comments