diff --git a/formulus/fastlane/metadata/android/en-US/changelogs/2.txt b/formulus/fastlane/metadata/android/en-US/changelogs/2.txt new file mode 100644 index 000000000..e4c65689f --- /dev/null +++ b/formulus/fastlane/metadata/android/en-US/changelogs/2.txt @@ -0,0 +1 @@ +Initial release of Formulus - offline-first mobile data collection app for field data collection and synchronization. diff --git a/synkronus/pkg/appbundle/appinfo_test.go b/synkronus/pkg/appbundle/appinfo_test.go index b667547b8..97adab9a8 100644 --- a/synkronus/pkg/appbundle/appinfo_test.go +++ b/synkronus/pkg/appbundle/appinfo_test.go @@ -3,18 +3,10 @@ package appbundle import ( "archive/zip" "bytes" - "context" "encoding/json" - "io" - "os" - "path/filepath" - "slices" - "strconv" - "strings" "sync" "testing" - "github.com/opendataensemble/synkronus/pkg/logger" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -219,227 +211,3 @@ func TestGenerateAppInfo_ErrorCases(t *testing.T) { }) } } - -func TestBundleChanges_FieldAddition(t *testing.T) { - // Initialize the service with test configuration - tempDir := t.TempDir() - logger := logger.NewLogger() - service := NewService(Config{ - BundlePath: filepath.Join(tempDir, "bundle"), - VersionsPath: filepath.Join(tempDir, "versions"), - MaxVersions: 5, - }, logger) - - // Initialize the service - err := service.Initialize(context.Background()) - require.NoError(t, err, "Failed to initialize service") - - // First, upload the initial bundle (valid_bundle01.zip) - bundle01Path := filepath.Join("..", "..", "testdata", "bundles", "valid_bundle01.zip") - bundle01File, err := os.Open(bundle01Path) - require.NoError(t, err, "Failed to open bundle01") - defer bundle01File.Close() - - _, err = service.PushBundle(context.Background(), bundle01File) - require.NoError(t, err, "Failed to push initial bundle") - - // Get the version number of the first bundle - versions, err := service.GetVersions(context.Background()) - require.NoError(t, err, "Failed to get versions") - require.GreaterOrEqual(t, len(versions), 1, "Expected at least one version") - // Not "published" version yet - version1 := versions[0] - require.NotContains(t, version1, " *") - - // Switch to the first version - err = service.SwitchVersion(context.Background(), version1) - require.NoError(t, err, "Failed to switch to first version") - - // Now check that version 0001 is active (has asterisk) - versions, err = service.GetVersions(context.Background()) - require.NoError(t, err, "Failed to get versions") - require.GreaterOrEqual(t, len(versions), 1, "Expected at least one version") - version1 = versions[0] - require.Contains(t, version1, " *") - - // Verify current manifest is for version 1 - manifest, err := service.GetManifest(context.Background()) - require.NoError(t, err, "Failed to get manifest") - require.Equal(t, strings.TrimSuffix(version1, " *"), manifest.Version) - - // Then upload the second bundle (valid_bundle02.zip) - bundle02Path := filepath.Join("..", "..", "testdata", "bundles", "valid_bundle02.zip") - bundle02File, err := os.Open(bundle02Path) - require.NoError(t, err, "Failed to open bundle02") - defer bundle02File.Close() - - _, err = service.PushBundle(context.Background(), bundle02File) - require.NoError(t, err, "Failed to push second bundle") - - // Verify current manifest is still for version 1 - manifest, err = service.GetManifest(context.Background()) - require.NoError(t, err, "Failed to get manifest") - require.Equal(t, strings.TrimSuffix(version1, " *"), manifest.Version) - require.False(t, slices.ContainsFunc(manifest.Files, func(f File) bool { - return f.Path == "app/THIS_IS_VERSION_2.txt" - }), "Expected NOT to find file with path 'app/THIS_IS_VERSION_2.txt' in manifest") - - // Try downloading app/THIS_IS_VERSION_2.txt - expect it to fail - nofile, _, err := service.GetFile(context.Background(), "app/THIS_IS_VERSION_2.txt") - require.Error(t, err, "Expected to fail to download file") - require.Empty(t, nofile) - - // Switch to the second version - preVersions, err := service.GetVersions(context.Background()) - require.NoError(t, err, "Failed to get versions") - require.GreaterOrEqual(t, len(preVersions), 2, "Expected at least two versions") - require.Contains(t, preVersions, "0001 *") - require.Contains(t, preVersions, "0002") - - err = service.SwitchVersion(context.Background(), "0002") - require.NoError(t, err, "Failed to switch to second version") - - // Get the version number of the second bundle - versions, err = service.GetVersions(context.Background()) - require.NoError(t, err, "Failed to get versions") - require.GreaterOrEqual(t, len(versions), 2, "Expected at least two versions") - version2 := strings.TrimSuffix(versions[0], " *") // Get the latest version - - // Verify current manifest is for version 2 - manifest, err = service.GetManifest(context.Background()) - require.NoError(t, err, "Failed to get manifest") - require.Equal(t, strings.TrimSuffix(version2, " *"), manifest.Version) - require.True(t, slices.ContainsFunc(manifest.Files, func(f File) bool { - return f.Path == "app/THIS_IS_VERSION_2.txt" - }), "Expected to find file with path 'app/THIS_IS_VERSION_2.txt' in manifest") - - // Try downloading app/THIS_IS_VERSION_2.txt - file, _, err := service.GetFile(context.Background(), "app/THIS_IS_VERSION_2.txt") - require.NoError(t, err, "Failed to download file") - fileContent, err := io.ReadAll(file) - defer file.Close() - require.NoError(t, err, "Failed to read file content") - require.Equal(t, "Something...", string(fileContent)) - - // Compare the two versions - changeLog, err := service.CompareAppInfos(context.Background(), strings.TrimSuffix(version1, " *"), strings.TrimSuffix(version2, " *")) - require.NoError(t, err, "Failed to compare app infos") - - // Verify that the changes include the addition of the "lastname" field - foundLastnameAddition := false - for _, modifiedForm := range changeLog.ModifiedForms { - for _, addedField := range modifiedForm.AddedFields { - if addedField.Name == "lastname" { - foundLastnameAddition = true - break - } - } - if foundLastnameAddition { - break - } - } - - assert.True(t, foundLastnameAddition, "Expected to find 'lastname' field addition in changes") - - // Verify the ChangeLog structure is as expected - // Convert version numbers to integers for comparison (e.g., "0001" -> 1, "0002" -> 2) - version1Num, _ := strconv.Atoi(strings.TrimSuffix(version1, " *")) - version2Num, _ := strconv.Atoi(strings.TrimSuffix(version2, " *")) - compareVersionANum, _ := strconv.Atoi(changeLog.CompareVersionA) - compareVersionBNum, _ := strconv.Atoi(changeLog.CompareVersionB) - - assert.Equal(t, version1Num, compareVersionANum, "CompareVersionA should match the first version") - assert.Equal(t, version2Num, compareVersionBNum, "CompareVersionB should match the second version") - assert.True(t, changeLog.FormChanges, "Expected form changes between versions") - - // Verify we have exactly one modified form - assert.Len(t, changeLog.ModifiedForms, 1, "Expected exactly one modified form") - if len(changeLog.ModifiedForms) > 0 { - modifiedForm := changeLog.ModifiedForms[0] - assert.True(t, modifiedForm.SchemaChange, "Expected schema changes in the modified form") - assert.False(t, modifiedForm.CoreChange, "Did not expect core field changes") - } -} - -func TestPushBundleGeneratesAppInfo(t *testing.T) { - tests := []struct { - name string - bundlePath string - assertions func(t *testing.T, appInfo *AppInfo) - }{ - { - name: "valid bundle 01", - bundlePath: filepath.Join("..", "..", "testdata", "bundles", "valid_bundle01.zip"), - assertions: func(t *testing.T, appInfo *AppInfo) { - assert.NotEmpty(t, appInfo.Version, "Version should not be empty") - assert.NotEmpty(t, appInfo.Forms, "Should have forms") - assert.Equal(t, 7, len(appInfo.Forms["example"].Fields), "Should have 7 fields") - }, - }, - { - name: "valid bundle 02", - bundlePath: filepath.Join("..", "..", "testdata", "bundles", "valid_bundle02.zip"), - assertions: func(t *testing.T, appInfo *AppInfo) { - assert.NotEmpty(t, appInfo.Version, "Version should not be empty") - assert.NotEmpty(t, appInfo.Forms, "Should have forms") - assert.Equal(t, 8, len(appInfo.Forms["example"].Fields), "Should have 8 fields") - }, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - // Create a temporary directory for testing - tempDir := t.TempDir() - - // Initialize the service with test configuration - config := Config{ - BundlePath: filepath.Join(tempDir, "bundle"), - VersionsPath: filepath.Join(tempDir, "versions"), - MaxVersions: 5, - } - - service := NewService(config, logger.NewLogger()) - - // Initialize the service - err := service.Initialize(context.Background()) - require.NoError(t, err, "Failed to initialize service") - - // Open the test bundle - bundleFile, err := os.Open(tc.bundlePath) - require.NoError(t, err, "Failed to open test bundle") - defer bundleFile.Close() - - // Push the bundle - _, err = service.PushBundle(context.Background(), bundleFile) - require.NoError(t, err, "Failed to push bundle") - - // Get the app info for the pushed bundle - versions, err := service.GetVersions(context.Background()) - require.NoError(t, err, "Failed to get versions") - require.NotEmpty(t, versions, "Expected at least one version") - - version := versions[0] - // Remove the " *" suffix if present (indicates current version) - version = strings.TrimSuffix(version, " *") - - appInfo, err := service.GetAppInfo(context.Background(), version) - require.NoError(t, err, "Failed to get app info") - - // Run test-specific assertions - tc.assertions(t, appInfo) - - // Common assertions - assert.NotEmpty(t, appInfo.Version, "App version should not be empty") - assert.NotEmpty(t, appInfo.Timestamp, "Timestamp should be set") - - // Log the generated app info for debugging - t.Logf("Generated app info: %+v", appInfo) - - // Verify the APP_INFO.json file exists in the version directory - appInfoPath := filepath.Join(config.VersionsPath, version, "APP_INFO.json") - _, err = os.Stat(appInfoPath) - assert.NoError(t, err, "APP_INFO.json should exist in the version directory") - }) - } -} diff --git a/synkronus/testdata/bundles/valid_bundle01.zip b/synkronus/testdata/bundles/valid_bundle01.zip deleted file mode 100644 index d14176f9b..000000000 Binary files a/synkronus/testdata/bundles/valid_bundle01.zip and /dev/null differ diff --git a/synkronus/testdata/bundles/valid_bundle02.zip b/synkronus/testdata/bundles/valid_bundle02.zip deleted file mode 100644 index c006805cd..000000000 Binary files a/synkronus/testdata/bundles/valid_bundle02.zip and /dev/null differ