Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions formulus/fastlane/metadata/android/en-US/changelogs/2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Initial release of Formulus - offline-first mobile data collection app for field data collection and synchronization.
232 changes: 0 additions & 232 deletions synkronus/pkg/appbundle/appinfo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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")
})
}
}
Binary file removed synkronus/testdata/bundles/valid_bundle01.zip
Binary file not shown.
Binary file removed synkronus/testdata/bundles/valid_bundle02.zip
Binary file not shown.
Loading